DEV recently added DEV Community Buddy BETA to the post editor, giving writers an AI assistant for Markdown, formatting, embeds, and community guidelines.
The idea is useful. The execution still feels like a chatbot placed beside the editor.
When I tested it, the assistant could explain how to complete a task, but it could not perform that task inside the writing workflow. It did not clearly show what part of the draft it could access, how long the conversation context would persist, or whether the session belonged to the current post. Opening the assistant also reduced the editor space and created a separate interface that competed with the writing experience.
That made me curious about a larger question:
What would DEV Community Buddy look like if it could understand the active draft and safely take actions inside the editor?
Since DEV runs on Forem, an open-source community platform, I downloaded the project and set it up locally. I then started integrating the open-source YourGPT Copilot SDK to turn the assistant from a passive question-and-answer panel into an editor-aware copilot.
The goal is not to replace DEV’s beta or dismiss an early experiment. It is to explore the next step: an assistant that can read the current writing context, rewrite selected text, insert Markdown, suggest tags, prepare cover-image prompts, and apply approved changes without forcing the writer to copy and paste everything manually.
This post is that exploration: how I built it, how others can reproduce it, and how the same pattern can extend beyond the editor (stats, reading lists, account settings). Credit to @ben , @jess and everyone who maintains DEV and Forem—the open platform and editor this depends on. If the product team reads this, treat it as a field report: keep what helps, ignore what does not. Actionable tools in the draft (and later across the product) are the direction I found useful to implement and document.
Demo
The problem I was trying to solve
DEV Community Buddy can already help with basic writing questions. It can explain Markdown, suggest wording, answer questions about DEV, and generate text inside the side panel.
The limitation is what happens after the answer appears.
I was not trying to build a better chatbot for brainstorming. I wanted the copilot to complete the small, repetitive actions that slow writers down while finishing a post:
- “Fill four relevant tags” → the tag fields are populated
- “Tighten this paragraph” → the selected paragraph is replaced
- “Add a TL;DR” → a formatted section appears at the top
- “Write an introduction for this title” → the title remains unchanged and the introduction is inserted into the body
- “Outline the remaining sections” → Markdown is added at the current cursor position
- “Convert this Mermaid diagram” → a PNG is generated and inserted into the post
- “Create a cover image” → the image is generated and connected to the article
- “Proofread this selection” → corrections are applied without replacing the rest of the draft
- “Add citations” → relevant sources are found and inserted in the correct format
A side panel that only returns text still leaves the writer with the same workflow:
select → ask → copy → paste → repair formatting → return to writing
That is useful during ideation. It becomes friction when the draft is nearly complete.
The important context already exists inside the product:
- Article title
- Tags
- Body content
- Selected text
- Cursor position
- Focused field
- Current draft
- Authentication and CSRF state
The copilot should use that state instead of asking the author to repeatedly describe or paste it.
The design principle was simple:
The model decides what should change. Product-side handlers decide how that change is safely applied.
The model does not directly manipulate the page. It selects from a controlled set of tools such as updateTags, replaceSelection, insertMarkdown, or generateImage. Forem remains responsible for validating and applying each change.
This creates a clear separation of responsibility:
- The model interprets the author’s intent
- Client tools expose permitted product actions
- Forem handlers update the real interface
- Sensitive credentials remain on the server
- The author reviews the result inside the existing workflow
- Generated content does not need to be copied back manually
This is the difference between adding AI beside a product and making the product operable through AI.
The implementation follows the client-tool pattern provided by the YourGPT Copilot SDK.
How I Turned DEV Community Buddy Into an Action-Capable Copilot
In my version, DEV Community Buddy is no longer a detached assistant that only returns suggestions inside a side panel.
Using the YourGPT Copilot SDK, I connected Buddy to a controlled set of tools that can read the current article state and perform actions directly inside the DEV writing experience.
Each tool is bound to a specific part of the post, including the title, tags, body, selected text, and media.
Actions connected to the article editor
| Request | What Buddy does |
|---|---|
| Set or improve the title | Updates the title field as plain text without adding a Markdown #
|
| Fill the tags | Selects up to four relevant tags through Forem’s existing chip interface |
| Write an introduction, outline, or section | Inserts Markdown at the cursor, start, or end of the article |
| Rewrite the full article | Replaces the body only when the request clearly applies to the complete draft |
| Rewrite selected text | Replaces only the highlighted text |
| Make selected text shorter | Condenses the selection without changing the surrounding content |
| Proofread selected text | Fixes grammar, spelling, and clarity in place |
| Add a TL;DR | Generates and inserts a formatted ## TL;DR section at the top |
| Generate a cover image | Creates an article image and connects it to the publishing workflow |
| Convert Mermaid to PNG | Renders a Mermaid diagram as an image and inserts it into the article |
| Add citations | Finds relevant sources and inserts citations where they are needed |
| Continue writing | Uses the existing draft and cursor position to extend the article naturally |
The important difference is that every request maps to a real product action.
Buddy does not simply return a paragraph and leave the author to decide where it belongs. It understands whether the result should update the title, populate the tag fields, replace selected text, or insert Markdown at a particular position.
Editor behavior that mattered in practice
| Behavior | Why it matters |
|---|---|
| Replace only the selected text | Prevents a small edit from accidentally changing the full draft |
| Insert at the cursor, start, or end | Adds content where the author expects it |
| Add the TL;DR at the top | Creates the correct article structure automatically |
| Remove a leading H1 from generated body content | DEV already stores the title in a separate field |
| Preserve the selected range | Keeps the correct text available after focus moves to the copilot |
| Use the real tag chip interface | Preserves Forem’s existing validation and interaction patterns |
| Apply every action once | Prevents duplicate text, repeated tags, or multiple insertions |
| Keep API keys off the client | Ensures sensitive credentials remain on the server |
| Require controlled tools | Limits the model to actions explicitly exposed by the product |
These details may sound small, but they determine whether the copilot feels reliable.
Generating good text is only one part of the problem. The system must also know where that text belongs, what it is allowed to change, and how to apply the result without damaging the rest of the article.
Selection-aware editing
The fastest editing workflow does not begin inside the copilot panel.
The author highlights a sentence or paragraph and chooses an action from the contextual toolbar:
Rewrite · Shorter · Proofread · Add citation
For example:
Rewrite
> Ever wondered what actually happens inside a Transformer?
Before the copilot opens, the editor stores the selected range. The model then returns an improved version, and the apply_selection_edit tool replaces that exact range.
The interaction works like this:
- The author highlights text
- The editor stores the selection range
- The author chooses an action
- The copilot receives the selected content
- The model generates the requested revision
- Forem replaces only the stored selection
Buddy does not need to be open before the author selects text.
The user also does not need to copy the response, return to the editor, find the original paragraph, paste the new version, and repair the formatting.
The change happens exactly where the writing already lives.
Draft-aware content insertion
Buddy also understands that different types of generated content belong in different places.
A title should update the title field.
Tags should become chips.
A TL;DR should appear near the top.
A new section should be inserted at the cursor or added to the end.
A full rewrite should replace the body only when the author clearly requests it.
This avoids one of the most common problems with generic AI writing tools: they generate useful content without understanding the structure of the product receiving it.
In my implementation, the model chooses the intended action, but Forem controls how that action is applied.
For example, the model can request:
{
"tool":"insert_markdown",
"position":"cursor",
"content":"## How attention works\n\n..."
}
Or:
{
"tool":"update_tags",
"tags": ["ai","machinelearning","javascript","tutorial"
]
}
The client-side handler validates the request and updates the corresponding part of the editor.
Media generation inside the writing flow
I also wanted Buddy to handle tasks that normally require leaving the editor.
For Mermaid diagrams, the author can provide or select Mermaid syntax and ask Buddy to convert it into a PNG. The diagram is rendered, uploaded, and inserted back into the article as Markdown.
For article visuals, Buddy can generate a cover image or supporting image based on the title and draft context.
The goal is not merely to return an image prompt. The goal is to complete the usable workflow:
- Understand what image the article needs
- Generate or render the image
- Make the result available to the article
- Insert or assign it in the correct place
That is the difference between explaining how to add media and actually helping the author add it.
Automatic tags and TL;DR generation
Tags and summaries are small tasks, but they interrupt the final publishing flow.
Buddy can analyse the title and article body, select up to four relevant DEV tags, and populate the existing tag fields.
It can also generate a concise TL;DR and insert it at the top of the article using consistent Markdown:
## TL;DR
A concise summary of the article appears here.
The author can still edit or remove the result, but the mechanical work is already complete.
Architecture
Three processes:
- Tools run against product state (DOM handlers for the form; later, APIs for member data). The model only emits tool names and arguments.
- Runtime uses official SSE (server docs), not raw plain text.
- Rails enforces session and CSRF. Model keys stay on the Node process.
Product-level extensions use the same spine. You change context and tools, not the overall shape.
How to split responsibilities
Long tool catalogs in the system prompt waste tokens and hurt tool choice. This split worked better:
| Layer | Role |
|---|---|
| systemPrompt | Persona and product rules (e.g. title ≠ body H1) |
| tool descriptions | Short when/how (one sentence when possible) |
body() each request |
Live snapshot (article_state, later other *_state) |
| handlers | Validation and mutations |
| Skills (optional) | Process notes, not DOM writes |
- Attach draft state every turn; do not call “read draft” on every greeting.
- Keep internal tool instructions out of the visible user message.
Then multi-part requests can become multiple tool calls in one turn (title + tags + body).
Setup on local Forem
Stack used: Forem + @yourgpt/copilot-sdk / @yourgpt/llm-sdk 2.5.x.
Prerequisites
- Forem local environment (Ruby, Postgres, Redis, Node 20, Yarn)
- Provider API key (Gemini used here)
- Node runtime process alongside Rails
Packages
yarn add @yourgpt/copilot-sdk @yourgpt/llm-sdk openai
Environment
GOOGLE_API_KEY="…"
COPILOT_MODEL="gemini-3.6-flash"
COPILOT_FALLBACK_MODELS="gemini-3.5-flash-lite,gemini-3.5-flash,gemini-flash-lite-latest"
COPILOT_RUNTIME_URL="http://127.0.0.1:3101/api/copilot/stream"
COPILOT_RUNTIME_PORT=3101
Primary model: gemini-3.6-flash. Fallbacks help when the free tier returns 429.
Runtime
yarn copilot:runtime
curl -s http://127.0.0.1:3101/health
Per request: parse body → restore Gemini thought signatures when needed → stream via createRuntime.
Rails
post "/api/copilot", to: "copilot#chat"
Authenticate the user, proxy to COPILOT_RUNTIME_URL, stream text/event-stream, map failures to short messages. Do not show provider internals (e.g. thought_signature) in the UI.
Frontend
- Mount node:
#article-copilot-sdk-root - Pack:
app/javascript/packs/copilotSdk.js - Keep
CopilotProvidermounted when the dock is closed; only portal the panel when open. Selection actions needsendMessagewithout the dock.
<CopilotProvider
runtimeUrl="/api/copilot"
systemPrompt={SYSTEM_PROMPT}
streaming
maxIterations={12}
headers={() => ({
'X-CSRF-Token': csrfToken(),
Accept: 'text/event-stream',
})}
body={() => ({ article_state: collectArticleState() })}
>
<ArticleEditorTools />
<SelectionToolbar onOpen={openDock} />
{isOpen && createPortal(<BuddyPanel onClose={closeDock} />, document.body)}
</CopilotProvider>
Tools
Prefer JSON Schema on inputSchema, short descriptions, and { success: true/false, … } from handlers.
useTools({
set_article_title: {
description: 'Set the post title field (plain text, not markdown).',
inputSchema: {
type: 'object',
properties: { title: { type: 'string' } },
required: ['title'],
additionalProperties: false,
},
handler: async ({ title }) => {
const clean = cleanArticleTitle(title);
const ok = setNativeValue(titleEl, clean);
return { success: ok, title: clean, _aiResponseMode: 'brief' };
},
},
insert_into_body: {
description:
'Insert body markdown (start|end|cursor). No leading H1; title is separate.',
},
apply_selection_edit: {
description:
'Replace selected body text once (Rewrite/Shorter). New text only; do not call again.',
aiResponseMode: 'none',
},
});
- Strip a single leading
# Titlefrom body inserts so the title field is not duplicated. - On Rewrite/Shorter, store
{ start, end, text }before focus moves; clear after one successful apply to avoid retry loops.
CSS and build
@source "../../../node_modules/@yourgpt/copilot-sdk/dist/**/*.{js,ts,jsx,tsx}";
yarn build:copilot-css && yarn build
Checks
-
/healthreports the configured model - Create Post shows the launcher when logged in
- Tags update as chips
- Title / tags / body update in the form, not only in chat
- Selection Rewrite works with the dock closed first
- Body does not start with a duplicate H1 title
- Gemini tool follow-ups do not return 400
| Piece | Path |
|---|---|
| UI | app/javascript/article-form/components/CopilotSDK/index.jsx |
| Tools | …/ArticleEditorTools.jsx |
| DOM | …/editorDom.js |
| Selection | …/SelectionToolbar.jsx |
| Tool UI | …/ToolCards.jsx |
| Runtime | services/copilot-runtime/server.mjs |
| Proxy | app/controllers/copilot_controller.rb |
| Pack | app/javascript/packs/copilotSdk.js |
Docs: getting started · server · frontend tools · agentic loop · generative UI
Gemini 3 tool follow-ups
Gemini 3.x expects a thought signature on function calls for follow-up turns (docs, OpenAI compatibility):
"tool_calls": [{
"id": "…",
"type": "function",
"function": { "name": "apply_selection_edit", "arguments": "{…}" },
"extra_content": { "google": { "thought_signature": "…" } }
}]
If history is rebuilt without extra_content, the next request often fails with 400. Cache signatures by tool-call id while streaming, re-attach them on the next request, and normalize field names (tool_calls, tool_call_id). Prefer fixing that over permanently downgrading the model to avoid the issue.
Multi-tool turns also hit rate limits more easily on free tiers. Surface a clear retry message; optional fallback models help.
Small product choices that improved the feel
- Toolbar messages: action label + quoted selection only
- One apply per selection edit
- Title in the title field; body without a leading H1
- Short confirmation after tools
- Keep title/tags/body tools available without deferred search on multi-step turns
- Provider mounted whenever selection tools need
sendMessage - User-facing errors without provider jargon
Extending the same Copilots beyond writing
The editor integration is one vertical. The reusable part is the loop:
- Authenticated SSE
- Context on every request
- Tools that change real product state
- Short chat around those tools
Other surfaces can reuse runtime + proxy + CopilotProvider. You swap the context object and the tool set.
Editor Extension surfaces
────── ──────────────────
article_state stats_state | reading_state | account_state
set_article_title summarize / list tools (read)
fill_tags pin_list / update_pref (write, often with confirm)
insert_into_body navigate / open section
apply_selection_edit
I did not fully implement stats, reading-list, or settings copilots. Below is a practical map so someone continuing from this work knows what to add.
Rules that still apply
| Rule | Reason |
|---|---|
Put live data in body(), not a mandatory “read all” tool every turn |
Fewer wasted tool rounds |
| Tools only perform actions the member can already perform | Matches product permissions |
| Keep tool descriptions short | Better tool choice, smaller schemas |
| Keep user-visible messages free of internal instructions | Clearer chat |
| Prefer one-shot mutations where possible | Avoid loops |
| Confirm destructive or account-wide changes | Especially settings |
| Never put secrets in model context | Tokens, passwords, raw session ids |
Stats
Goal: explain numbers the member can already see, and suggest a next writing step from real data—not invented metrics.
Context example:
body: () => ({
surface: 'dashboard',
stats_state: {
range: '30d',
totals: { views, reactions, comments, followers_delta },
top_posts: [{ id, title, views, reactions, published_at }],
series: [{ date, views }],
},
})
Example tools: get_stats_snapshot, list_top_posts, open_post_analytics, suggest_followup_topics (text only from provided posts), optional bridge to editor tools for an outline.
Example questions: why views changed; which posts to turn into a series; what to write next given top tags.
Constraint: if a figure is not in context or a tool result, say so. Do not invent analytics.
Reading list
Goal: build a short, personal queue from real posts (search/save/follow APIs), not hallucinated links.
Context example: followed tags, recent reads, saves, optional goals.
Example tools: search_posts, build_reading_list, pin_reading_item, save_for_later, follow_tag / mute_tag (with confirmation), export_reading_list.
Example questions: weekend list on a topic; next reads based on history; pin three and drop already-read items.
Constraint: every recommended URL/id should come from a tool or injected state.
Account and settings
Goal: explain settings and, where safe, apply changes the member already has UI for—without dumping secrets into the prompt.
Context example: profile completeness flags, notification toggles, 2FA on/off, session count—not passwords or raw tokens.
Example tools: open_settings_section, update_notification_pref (confirm), update_profile_field (confirm for public fields), list_sessions, revoke_session (confirm), explain_setting (read-only).
Example questions: reduce email noise; complete public profile; review sessions.
Constraint: prefer navigate + explain by default; mutate only with confirmation (needsApproval or equivalent). Stricter than the editor.
Implementation order for an extension
- Choose one surface.
- Define a
*_statepayload you can collect safely. - Add a small tool pack (about 4–8 tools) with short descriptions.
- Mount
CopilotProvideron that page; passsurface+ state inbody(). - Reuse the existing runtime and Rails proxy.
- Adjust the system prompt for that surface only.
- Test normal prompts and refusal cases (“delete my account” without a tool, etc.).
- Optionally connect back to the editor (e.g. stats → outline →
insert_into_body).
Prompt for an AI coding agent
Paste this into Cursor, Claude Code, Codex, or similar when you want the agent to set up the same stack on a Forem (or similar) codebase:
You are implementing an editor-aware writing copilot on Forem using the YourGPT Copilot SDK
(@yourgpt/copilot-sdk + @yourgpt/llm-sdk ~2.5.x), matching this architecture:
ARCHITECTURE
- Browser: CopilotProvider (always mounted) + useTools handlers + SelectionToolbar
+ CopilotChat portaled in a right dock when open
- Rails: authenticated POST /api/copilot streams SSE to the Node runtime (CSRF + session)
- Node: services/copilot-runtime/server.mjs with createRuntime, Gemini 3.x primary model
(COPILOT_MODEL=gemini-3.6-flash), thought_signature cache/restore on tool follow-ups,
optional model fallbacks on 429
- Never put API keys in the client. Never stream text/plain to CopilotChat.
DOCS (prefer over memory)
- https://copilot-sdk.yourgpt.ai/docs/getting-started
- https://copilot-sdk.yourgpt.ai/docs/server
- https://copilot-sdk.yourgpt.ai/docs/tools/frontend-tools
- https://copilot-sdk.yourgpt.ai/docs/tools/agentic-loop
- https://copilot-sdk.yourgpt.ai/docs/generative-ui
- https://ai.google.dev/gemini-api/docs/thought-signatures
FILE MAP TO CREATE/UPDATE
app/javascript/article-form/components/CopilotSDK/
index.jsx, SelectionToolbar.jsx, ArticleEditorTools.jsx, editorDom.js,
ToolCards.jsx, toolSchemas.js
app/javascript/packs/copilotSdk.js
app/assets/stylesheets/copilot-sdk.css (Tailwind @source SDK dist; FAB + dock + selection pill)
app/controllers/copilot_controller.rb
config/routes.rb → post "/api/copilot"
services/copilot-runtime/server.mjs
.env: GOOGLE_API_KEY, COPILOT_MODEL, COPILOT_RUNTIME_URL, COPILOT_FALLBACK_MODELS
UI REQUIREMENTS (match this UX)
- Floating launcher (avatar + BETA badge) bottom-right above article actions
- Right full-height dock (~400px) with official CopilotChat (csdk-theme-modern)
- Provider ALWAYS mounted; only dock portals when open; body class buddy-dock-open
- Selection toolbar on body highlight: Rewrite + Shorter only (no internal prompts in chat)
- User message format: "Rewrite\n\n> selected text" (blockquote). Tool policy in system
prompt + tool descriptions, not in the bubble
- On toolbar click: setPendingBodySelection({start,end,text}), open dock, sendMessage
- apply_selection_edit once using pending range; clear pending; do not loop
- Live article_state (title, tags, body) in CopilotProvider body() every request
- Strip leading H1 from body inserts; title is a separate plain-text field
- Short friendly parseError messages; never show thought_signature to users
- toolRenderers for tags/cover/mermaid/TL;DR; ToolStep titles for simple tools
- local thread persistence key: dev-community-buddy-threads
TOOLS (inputSchema JSON Schema, short descriptions)
set_article_title, fill_tags, insert_into_body, replace_article_body,
apply_selection_edit (eager, one-shot), generate_tldr, generate_cover_image,
mermaid_to_png; optional get_article_draft (not on every greeting)
LAYERING
systemPrompt = persona + product rules only (no tool catalog)
tool descriptions = short decision boundaries
body() = live state
handlers = DOM mutations, return { success, ... }
VERIFY
yarn build:copilot-css && yarn build
yarn copilot:runtime → curl health
Logged-in Create Post: launcher, tags chips, multi-tool title+tags+body,
selection Rewrite with dock closed first, no body H1 title, no 400 on tool follow-up
If something fails, fix signatures / selection pending range / Provider mount first—
do not downgrade Gemini major solely to hide tool-follow-up 400s unless the user asks.
FAQ
Is this the official DEV Community Buddy?
No. This is an independent fan-built experiment using Forem. It is not affiliated with, endorsed by, or deployed by DEV.to Community. I built it to explore a more efficient and action-capable version of Buddy could look like, especially one that can understand the article context, work directly with the editor, and help developers write and publish with less manual effort.
Why did you build it on Forem?
DEV Community at dev.to is built on Forem, its open-source community platform. After testing the first beta version of DEV Community Buddy, I found it useful for basic writing guidance, but it still behaved more like a chatbot than an integrated product copilot. I wanted to explore a more capable experience that could help developers write better posts with less manual work, so I ran the same Forem foundation behind dev.to locally and connected it to the YourGPT Copilot SDK. The SDK made it possible to turn Buddy into an action-capable copilot that understands the live article state and can safely interact with the real writing interface. Instead of only suggesting text, it can update the title, fill relevant tags, rewrite or proofread selected content, insert a TL;DR, generate images, convert Mermaid diagrams into PNGs, add citations, and place Markdown in the correct location. This allowed me to build a more contextual and efficient writing workflow inside the actual product, rather than a separate AI demo that could not operate the editor.
What part of the project is actually implemented?
The editor copilot is implemented. It can work with the title, tags, article body, selected text, cursor position, TL;DR generation, Mermaid rendering, and media-related actions.
The stats, personalised reading list, account, and settings copilots are proposed extensions of the same architecture. They are not presented as completed features.
What is the YourGPT Copilot SDK?
The YourGPT Copilot SDK is an open-source framework for building AI copilots that can understand product context, use tools, and take actions inside an application. It provides the client components and runtime infrastructure for streaming conversations, frontend and backend tool execution, live application context, multi-step agent workflows, and generative UI. Rather than adding a standalone chatbot, it helps developers build a agentic copilot that is embedded into the product experience and can safely operate within the actions and permissions the application exposes.
Why use the YourGPT Copilot SDK instead of calling a model API directly?
A direct LLM API can generate text, but it does not automatically make an application agentic. The YourGPT Copilot SDK adds the orchestration layer required to build an action-capable AI copilot agent inside a product. It streams responses, passes live application context such as the current article title, tags, body, cursor position, and selected text, connects the model to controlled frontend tools, supports multi-step tool execution, and renders tool progress directly in the interface. This allows the copilot to do more than suggest content. It can safely update fields, replace selected text, insert Markdown, generate media, and complete approved actions on the user’s behalf. The core value of the SDK is not access to a particular AI model, but the infrastructure for turning model output into contextual, permissioned product actions.
Can I use a different model?
Yes. The architecture is model-independent. Gemini was used for this implementation, but another supported provider can be configured through the runtime.
Why did you use Gemini for this build?
Gemini was the primary model used while developing and testing the integration. It supported the tool-calling and image gen workflow needed for editor actions.
Why use frontend tools for editor actions?
The relevant state already exists in the browser, including the current selection, cursor position, unsaved body content, and focused field.
Frontend tools can operate on that live state without repeatedly saving the draft or sending unnecessary requests to the backend. Server-side tools are still more appropriate for protected data, external services, uploads, and account-level actions.
How does the copilot know what is in the current draft?
The application passes a structured article-state object with each request. It can include the title, tags, body, selected text, cursor position, and active surface.
This gives the AI current product context without requiring the author to paste the article into the conversation.
Can the copilot modify anything in the application?
Yes, Copilot can take action on an application by using the exposed tools.
Can this architecture work outside the DEV editor?
Yes. The same runtime, authenticated proxy, provider, and tool pattern can support other product surfaces.
For example:
- Analytics explanations using
stats_state - Personalised reading lists using real post-search tools
- Navigation and account assistance
- Notification preference management
- Profile updates with confirmation
The main changes are the context object, available tools, and permission rules.
Is the YourGPT Copilot SDK limited to React applications?
The client components used in this implementation are React-based, but the broader architecture is not limited to a particular backend. The runtime and tool pattern can be integrated with applications using Rails, Node, or other server environments.
The exact frontend integration depends on how the host application exposes state and actions.
Can this be used in production?
Absolutely. Both Forem and the YourGPT Copilot SDK are open source, so you can clone the repositories, fork them, modify the code, self-host the complete stack, and adapt this implementation for your own product. The YourGPT Copilot SDK is available under the permissive MIT License, while Forem is released under the GNU Affero General Public License v3.0
Closing
I wanted to build a copilot that understands a draft as live product state, not just text inside a chat window. It should know the title, tags, body, cursor position, and selected text, choose from a controlled set of tools, apply the requested change in the correct place, and stop once the editor has been updated.
That is what I built on a local Forem instance. The process also exposed the less visible problems behind an action-capable copilot: preserving selections after focus changes, preventing repeated tool execution, avoiding duplicate H1 titles, handling provider-specific tool follow-ups, and recovering cleanly from rate limits.
The same architecture can extend beyond writing. By changing the context and available tools, the copilot could explain article performance, curate a personalised reading list, navigate product settings, or complete other approved actions across the platform.
Forem’s open-source foundation made the experiment possible. The YourGPT Copilot SDK provided the agentic application layer for streaming, context, tool execution, and product actions. I have included the architecture, implementation notes, checks, and extension paths so other developers can reproduce the editor integration, improve it, or adapt the same pattern to their own products.
The larger lesson is simple: adding a chat panel gives users answers. Connecting an AI copilot to real product state and controlled tools gives them outcomes.


Top comments (0)