This guide builds a concrete reference integration for a SaaS code builder. The user asks for an application in chat; AgentChat reads the provisioned API contract, writes project files through the SaaS API, starts approved checks, fixes failures, deploys a Cloudflare Worker, and returns the preview URL. The code builder—not AgentChat—continues to own files, jobs, deployments, credentials, and the final project UI.
What AgentChat contributes to this workflow
AppForge does not implement a separate model tool for create_directory, write_file, run_build, and deploy_worker. It publishes those operations as normal HTTP APIs and registers one accurate API document in AgentChat. Every chat that attaches this document gains the complete coding capability pack through the built-in http_request tool.
AgentChat owns the asynchronous reasoning loop, durable messages, tool execution order, stop and continue behavior, and polling cursor. AppForge owns the operations and their authorization. This separation is the central design of the integration.
Step 1: expose a controlled AppForge API
The business API is intentionally narrower than a shell. Every path is resolved inside the authenticated project workspace, every mutation returns a revision, and build tasks are selected from an allowlist.
GET /v1/projects/{project_id}/tree
GET /v1/projects/{project_id}/files?path=src/index.ts
POST /v1/projects/{project_id}/directories
PUT /v1/projects/{project_id}/files
DELETE /v1/projects/{project_id}/files?path=src/old.ts
POST /v1/projects/{project_id}/checks
GET /v1/checks/{job_id}
POST /v1/projects/{project_id}/deployments
GET /v1/deployments/{deployment_id} AppForge validates the user token, verifies project membership, rejects path traversal, limits file size, and runs checks in an isolated environment. Cloudflare credentials remain inside AppForge. None of those secrets are written into the API document.
Step 2: write the document that the agent will actually receive
The document must include more than endpoint names. It must explain safe sequences, request fields, response fields, asynchronous polling, and how to recover from errors. The following shortened contract contains the rules that change agent behavior.
# AppForge Project API
Base URL: https://builder.example.com/v1
All paths are relative to the project workspace. Never use absolute paths or ../.
## Read project tree
GET /projects/{project_id}/tree
Returns entries with path, type, revision, and bytes. Read the tree before editing.
## Write complete file
PUT /projects/{project_id}/files
Body: path, content, expected_revision.
For a new file omit expected_revision. For an existing file, read it first and send its revision.
## Run approved check
POST /projects/{project_id}/checks
Body task is one of format, typecheck, test, build.
Returns job_id, status, poll_after_seconds. Start the job in one model turn. Wait and poll in a later turn.
## Read check
GET /checks/{job_id}
When failed, diagnostics contains file, line, category, and message. Fix the files and run the check again.
## Deploy validated revision
POST /projects/{project_id}/deployments
Body target=cloudflare-worker, environment=preview, revision. Only deploy the revision returned by a successful build.
Returns deployment_id and poll_after_seconds. Poll GET /deployments/{deployment_id} until succeeded or failed. Step 3: register that document through the AgentChat API
AppForge performs this provisioning from its backend by using an AgentChat user API key. The content field contains the complete contract above, not merely a link to documentation.
curl -X POST "$AGENT_CHAT_URL/api/api-documents"
-H "Authorization: Bearer ac_live_AGENT_CHAT_KEY"
-H "Content-Type: application/json"
--data '{
"title": "AppForge Project and Deployment API",
"description": "Read and modify a scoped project, run approved checks, and deploy a validated revision.",
"content": "# AppForge Project API\n\nBase URL: https://builder.example.com/v1\n...complete contract..."
}' The response returns a generated document ID. AppForge stores this ID as configuration for its coding-agent experience. Updating the registered document later changes the instructions available to subsequent chat turns without copying the document into every session.
{ "success": true, "data": { "id": "doc_uuid", "title": "AppForge Project and Deployment API" } } Step 4: create one AgentChat session for the current project user
When an AppForge user opens the coding assistant, the AppForge backend creates a session. It binds the selected LLM configuration, the project API document, operating limits, and a short-lived credential that can access only the current user’s project.
curl -X POST "$AGENT_CHAT_URL/api/agent/sessions"
-H "Authorization: Bearer ac_live_AGENT_CHAT_KEY"
-H "Content-Type: application/json"
--data '{
"title": "Build project prj_42",
"llm_config_id": "llm_config_uuid",
"api_document_ids": ["doc_uuid"],
"system_prompt": "You are the coding agent for project prj_42. Make focused changes, validate them, and deploy only after build succeeds.",
"max_turns": 30,
"tool_timeout_seconds": 120,
"tool_result_max_chars": 20000,
"host_headers": [
{ "host": "builder.example.com", "header_key": "Authorization", "header_value": "Bearer short_lived_project_token" },
{ "host": "builder.example.com", "header_key": "X-Project-ID", "header_value": "prj_42" }
]
}' Header values are write-only. AgentChat injects them only when the HTTP tool calls the matching host, and the model never receives their values. If a redirect changes the host, matching is evaluated again so project credentials are not carried to another service.
Step 5: start the coding run
curl -X POST "$AGENT_CHAT_URL/api/agent/sessions/session_uuid/chat"
-H "Authorization: Bearer ac_live_AGENT_CHAT_KEY"
-H "Content-Type: application/json"
--data '{ "message": "Create a feedback form as a Cloudflare Worker. Store submissions in the existing FEEDBACK KV binding, add validation, run the build, and deploy a preview." }' The endpoint returns immediately with state processing. It does not keep the SaaS request open while the model writes code. AgentChat acquires the processing lock and continues the run asynchronously.
{ "success": true, "data": { "session_id": "session_uuid", "state": "processing" } } What the agent does with the provisioned document
- Read the project tree and existing configuration through http_request.
- Read files that must be preserved, including their current revisions.
- Create directories and write the Worker source, validation logic, and configuration through AppForge APIs.
- Start the approved build job. Because tool calls from one model response run concurrently, the agent waits in a separate turn before polling the job.
- Read structured diagnostics. If the build fails, update the exact file and repeat the check.
- Submit the successful revision to the deployment endpoint, wait, and poll the deployment in later turns.
- Return the preview URL and a concise list of files changed.
Every visible step is persisted as an assistant or tool message. If the user stops the run or the maximum turn budget is reached, AppForge can call continue later and AgentChat resumes from durable history.
Step 6: poll durable messages from the AppForge frontend
AppForge polls once per second and keeps the last message ID and revision. A streaming assistant row keeps the same ID while its revision increases, so the client replaces that row instead of appending duplicates.
GET /api/agent/sessions/session_uuid/messages?after_id=last_message_uuid&after_revision=4
Authorization: Bearer ac_live_AGENT_CHAT_KEY
→ {
"success": true,
"data": {
"messages": [{ "id": "msg_uuid", "role": "assistant", "content": "Build passed...", "stream_status": "streaming", "revision": 5 }],
"last_id": "msg_uuid",
"last_revision": 5,
"is_processing": true,
"total_tokens": 8421
}
} The AppForge browser should call its own backend or a narrowly scoped proxy rather than receiving the long-lived AgentChat API key. The backend maps the AppForge user and project to the correct AgentChat session.
Step 7: display the deployed application from AppForge data
The deployment API writes deployment_id, project_id, revision, status, and preview_url into the AppForge database. After AgentChat completes, the existing deployment panel reads that table and displays the preview. The chat message is useful feedback, but it is not the system of record.
This is why the pattern extends cleanly: AgentChat coordinates operations, while AppForge remains responsible for the durable product state the rest of the application already knows how to display.
Production checklist for this exact integration
- Store the AgentChat document ID and LLM configuration ID as backend configuration.
- Issue short-lived project credentials when creating a session and scope them to one project.
- Reject absolute paths, traversal, escaped symlinks, oversized files, and unsupported extensions in AppForge.
- Expose named check tasks instead of arbitrary commands.
- Require a successful build revision before accepting a deployment request.
- Return job IDs and poll_after_seconds for checks and deployments.
- Poll AgentChat messages by both message ID and revision.
- Use stop for cancellation and continue for recoverable failures or exhausted turn budgets.
- Render files and deployments from the AppForge database, not by parsing final assistant text.