Documentation
Guides

Code Agents (Cursor-backed)

Create cloud code agents that work on GitHub repos, open PRs, and accept follow-up prompts — powered by Cursor's cloud SDK.

Code agents are cloud-based coding assistants backed by the Cursor SDK. You define a template (code agent) with a default repo, branch, model, and preamble, then launch sessions that clone the repo, execute your prompt, and optionally open a pull request.

Concepts

TermDescription
Code AgentA reusable template: default repo URL, branch, model, preamble, and PR behavior flags.
Code SessionA single execution of a template against a repo. Contains one or more messages, tracks status, and can produce a PR.
MessageA prompt sent to a session. The first message starts the session; subsequent messages are follow-ups on the same workspace.
EventA timestamped record of session activity (stdout, tool calls, file edits, etc.) streamed from the Cursor runtime.

Lifecycle

Create code agent template
  → Start session (POST /api/code-sessions)
    → Session status: pending → creating → running → finished/error/cancelled/expired
      → Send follow-up messages (POST /api/code-sessions/{id}/messages)
      → Cancel (POST /api/code-sessions/{id}/cancel)
      → Archive (POST /api/code-sessions/{id}/archive)

API Reference

All endpoints require Authorization: Bearer fj_live_....

Code Agent Templates

List Templates

GET /api/code-agents

Query parameters:

ParameterTypeDescription
orgIdstringTarget org (multi-org only)

Response 200:

[
  {
    "id": "ca-123",
    "org_id": "org-456",
    "name": "Bug Fixer",
    "description": "Fixes bugs from GitHub issues",
    "model_id": "auto",
    "model_params": null,
    "default_repo_url": "https://github.com/acme/app",
    "default_starting_ref": "main",
    "auto_create_pr": true,
    "work_on_current_branch": false,
    "skip_reviewer_request": false,
    "preamble": "You are a senior engineer. Fix the bug described in the prompt.",
    "created_by": "user-789",
    "created_at": "2026-05-06T12:00:00Z",
    "updated_at": "2026-05-06T12:00:00Z"
  }
]

Get Template

GET /api/code-agents/{codeAgentId}

Response 200: Full code agent object (same shape as list item, all fields populated).


Create Template

POST /api/code-agents

Request body:

FieldTypeRequiredDescription
namestringNoDisplay name (default: "New code agent")
descriptionstringNoWhat this template does
orgIdstringNoTarget org (multi-org only)
modelIdstringNoModel ID (default: "auto")
modelParamsobjectNoModel-specific parameters
defaultRepoUrlstringNoDefault GitHub repo URL
defaultStartingRefstringNoDefault branch (default: "main")
autoCreatePRbooleanNoAuto-create PR on completion (default: true)
workOnCurrentBranchbooleanNoWork directly on the starting ref instead of creating a new branch (default: false)
skipReviewerRequestbooleanNoSkip requesting reviewers on PRs (default: false)
preamblestringNoSystem prompt prepended to every session prompt

Response 201: The created code agent object.

curl -X POST https://api.flapjack.dev/api/code-agents \
  -H "Authorization: Bearer fj_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Bug Fixer",
    "defaultRepoUrl": "https://github.com/acme/app",
    "preamble": "Fix the bug described in the prompt. Write tests.",
    "autoCreatePR": true
  }'

Update Template

PATCH /api/code-agents/{codeAgentId}

Request body: Any of the create fields. Only include fields you want to change.

Response 200: The updated code agent object.


Delete Template

DELETE /api/code-agents/{codeAgentId}

Response 200: { "ok": true }


Code Sessions

List Sessions

GET /api/code-sessions

Query parameters:

ParameterTypeDescription
codeAgentIdstringFilter by template
statusstringFilter by status (pending, creating, running, finished, error, cancelled, expired)
archived"true" | "false"Filter by archived flag
orgIdstringTarget org (multi-org only)

Response 200:

[
  {
    "id": "cs-456",
    "org_id": "org-789",
    "code_agent_id": "ca-123",
    "cursor_agent_id": "cursor-abc",
    "repo_url": "https://github.com/acme/app",
    "starting_ref": "main",
    "status": "finished",
    "latest_run_id": "run-xyz",
    "pr_url": "https://github.com/acme/app/pull/42",
    "pr_branch": "fix/login-bug",
    "archived": false,
    "model_id": "auto",
    "created_at": "2026-05-20T10:00:00Z",
    "started_at": "2026-05-20T10:00:05Z",
    "completed_at": "2026-05-20T10:03:22Z"
  }
]

Start Session

POST /api/code-sessions

Creates a new session from a code agent template and immediately begins execution.

Request body:

FieldTypeRequiredDescription
codeAgentIdstringYesTemplate to run
promptstringYesThe task for the code agent
cursorApiKeystringYesCursor API key (encrypted at rest, cleared on archive)
orgIdstringNoTarget org (multi-org only)
repoUrlstringNoOverride template's default repo
startingRefstringNoOverride template's default branch
autoCreatePRbooleanNoOverride template's PR behavior
workOnCurrentBranchbooleanNoOverride template's branch behavior
skipReviewerRequestbooleanNoOverride template's reviewer behavior
modelIdstringNoOverride template's model
modelParamsobjectNoOverride template's model params
webhookUrlstringNoHTTPS URL for status webhooks

Response 201:

{
  "session_id": "cs-456",
  "message_id": "msg-001"
}
curl -X POST https://api.flapjack.dev/api/code-sessions \
  -H "Authorization: Bearer fj_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "codeAgentId": "ca-123",
    "prompt": "Fix the login bug in src/auth.ts — the JWT expiry check is off by one hour",
    "cursorApiKey": "cursor_..."
  }'

Get Session

GET /api/code-sessions/{codeSessionId}

Returns the session with its full message history.

Response 200:

{
  "id": "cs-456",
  "org_id": "org-789",
  "code_agent_id": "ca-123",
  "status": "finished",
  "pr_url": "https://github.com/acme/app/pull/42",
  "pr_branch": "fix/login-bug",
  "error": null,
  "archived": false,
  "webhook_url": null,
  "last_event_seq": 142,
  "last_event_at": "2026-05-20T10:03:22Z",
  "messages": [
    {
      "id": "msg-001",
      "cursor_run_id": "run-abc",
      "role": "user",
      "prompt": "Fix the login bug...",
      "status": "finished",
      "result_text": "Fixed the JWT expiry check...",
      "duration_ms": 197000,
      "pr_url": "https://github.com/acme/app/pull/42",
      "error": null,
      "started_at": "2026-05-20T10:00:05Z",
      "completed_at": "2026-05-20T10:03:22Z",
      "created_at": "2026-05-20T10:00:00Z"
    }
  ]
}

Update Session

PATCH /api/code-sessions/{codeSessionId}

Request body:

FieldTypeDescription
webhookUrlstring | nullUpdate or clear the webhook URL (must be public HTTPS)

Response 200: The updated session object.


Send Follow-Up Message

POST /api/code-sessions/{codeSessionId}/messages

Send a follow-up prompt to an existing session. The session must not be archived.

Request body:

FieldTypeRequiredDescription
promptstringYesFollow-up task

Response 201:

{ "message_id": "msg-002" }

Get Session Events

GET /api/code-sessions/{codeSessionId}/events

Read the event timeline for a session. Use since for polling.

Query parameters:

ParameterTypeDescription
sincenumberReturn events with seq greater than this value (default: 0)
messageIdstringFilter events to a specific message
limitnumberMax events to return (default: 200, max: 500)

Response 200:

{
  "events": [
    {
      "id": "evt-001",
      "session_id": "cs-456",
      "message_id": "msg-001",
      "cursor_run_id": "run-abc",
      "event_type": "tool_call",
      "payload": { "tool": "edit_file", "path": "src/auth.ts" },
      "seq": 1,
      "created_at": "2026-05-20T10:00:10Z"
    }
  ],
  "last_seq": 142
}

Poll pattern: call with since=0, then use the returned last_seq as since on subsequent calls.


Cancel Session

POST /api/code-sessions/{codeSessionId}/cancel

Cancel a running or creating session. Only sessions with status creating or running can be cancelled.

Response 200: { "ok": true, "status": "cancelled" }

Errors:

  • 502 cursor_cancel_failed — upstream Cursor cancel failed; retry
  • 409 CANCEL_UNSUPPORTED — the Cursor run doesn't support cancellation; wait for natural completion

Archive Session

POST /api/code-sessions/{codeSessionId}/archive

Archive a terminal session. This clears the encrypted Cursor API key from storage. The session must be in a terminal status (finished, error, cancelled, expired) — cancel active sessions before archiving.

Response 200: { "ok": true, "archived": true }

Errors:

  • 409 SESSION_ACTIVE — cancel the session first
  • 502 archive_failed — upstream archive failed; retry

MCP Tools

All code agent/session operations are available as MCP tools:

ToolDescription
flapjack_list_code_agentsList code-agent templates
flapjack_get_code_agentGet a template by ID
flapjack_create_code_agentCreate a new template
flapjack_update_code_agentUpdate a template
flapjack_delete_code_agentDelete a template
flapjack_list_code_sessionsList sessions (filter by template, status, archived)
flapjack_get_code_sessionGet session with messages
flapjack_start_code_sessionStart a new session from a template
flapjack_update_code_sessionUpdate session (webhookUrl)
flapjack_send_code_session_messageSend a follow-up prompt
flapjack_list_code_session_eventsRead session event timeline
flapjack_cancel_code_sessionCancel a running session
flapjack_archive_code_sessionArchive and clear stored key

Security Notes

  • The cursorApiKey is encrypted at rest using AES-256-GCM and never returned in API responses.
  • Archiving a session permanently clears the encrypted key.
  • webhookUrl must be a public HTTPS URL — private IPs and localhost are rejected.
  • Sessions use service-role writes with org isolation enforced by membership checks.
Docs last updated June 29, 2026