Latchkey
Lets coding agents read CI failures self-heal couldn't fix, check run status, dispatch workflows and run jobs on fresh Linux VMs.
Documentation
Documentation menu
Getting started Dashboard & analytics Managed runners
- Runners overview
- Run your first job
- Migrate from GitHub-hosted
- Latchkey CLI
- The Runners page
- Custom runners (AI Scan)
- Self-healing
- Runner image & software
- Provisioning & warm pools
- Limits & concurrency Caching Team & notifications
- Team & roles
- Notifications
- Slack integration Billing & plans
- Plans & trial
- Managing billing
- Usage & free minutes Help
- Troubleshooting
- FAQ
- Security architecture
- Security & permissions Workflow files
- Workflow files
Give Claude Code, Cursor, or any MCP-compatible agent secure access to your CI failures, plus opt-in workflow re-runs and one-off jobs on fresh runners, so it can triage, fix, and verify from your editor.
In short
- Settings, API keys and agents creates
lk_live_keys for Latchkey's MCP server athttps://latchkey.dev/mcp. - Connected agents (Claude Code, Cursor, any MCP client) can triage failures, pull failure bundles, check run status, tail logs, drive fixes from your editor, run one-off jobs on fresh runners, and list and cancel their jobs.
- The AI Insight page can hand a finding straight to your agent with Copy prompt or a Set up MCP shortcut.
- Keys are read-only by default, workspace-scoped, shown once at creation, and revocable at any time. Re-running workflows, reading CLI job status and logs, and running jobs are each a separate, explicit opt-in at key creation.
app.latchkey.dev / acme / settings
Settings, API keys and agents tab. The API keys panel, with 3 keys, walks three steps: 1 Details, 2 Copy key and 3 Connect agent. On step 2 the new key ci-agent-codex is shown once in full, under the warning Copy your key now. You will not be able to see it again. and the line that Latchkey stores only a hashed version. The continue button, I've saved it, continue, waits until the key is copied. The key is copied, and step 3 opens Connect your agent with Claude Code chosen: the command claude mcp add --transport http latchkey https://latchkey.dev/mcp --header "Authorization: Bearer" with the new key already filled in, a box to read the key from $LATCHKEY_API_KEY instead of pasting it, a note that the command writes the token in plaintext to ~/.claude.json, and the Latchkey CLI install command npm install -g @latchkeydev/cli. The command is copied. Under the steps, the Active table lists ci-agent-codex first, marked New, masked to its prefix lk_live_7f3a and its last four characters 3f2a, with access mcp:read, jobs:read and jobs:run, never used and never expiring, then deploy-bot, and cursor-ci marked Unused 30d.
FIG. 2.6-A The full key is shown once, when it is created; after that the list shows only its prefix and last four characters, and the access the key was created with never changes. Copy the key first: step 3 then gives the connect command with the key already in it.
Latchkey ships an MCP server: your AI coding agent connects to it with a Latchkey API key and can pull real CI failure context (failed runs, logs, diagnosis bundles) straight into your editor session. Instead of copy-pasting logs into a chat, your agent asks Latchkey directly and gets everything it needs to fix the failure.
This is the hand-off half of self-healing: self-healing fixes environment failures during the run and never touches your source, so when the real problem is a bug in your code, the build fails truthfully, and that failure arrives here as a ready-to-fix bundle for your agent.
There are two ways in: create a key yourself in Settings, API keys and agents (the setup below), or let the AI Insight page do it for you. Findings better fixed by your own coding agent offer Copy prompt, a ready-made prompt to paste into your agent, and a Set up MCP shortcut that creates a key named coding-agent and shows the exact connect command. The minted key expires in 90 days and can run one-off jobs on billable runners (the card says so next to the button), so treat it like the spend-capable credential it is.
What a connected agent can do
The server exposes thirteen capabilities: eleven tools your agent calls for data and actions, and two prompt flows that orchestrate a whole task:
List failed runstool
Enumerate recent failed workflow runs with their key metadata. Failed CLI jobs appear too.
Get failure bundletool
Pull the full context for one failure: logs, diagnosis, and workflow details.
Check run statustool
Poll a run Latchkey served for its status, conclusion, and per-job timing.
Tail run logstool
Read the secret-scrubbed log tail of any completed job, green runs included.
Re-run a workflowtool
Trigger a workflow_dispatch run to verify a fix. Requires a dispatch-enabled key.
Run a one-off jobtool
Run a shell command on a fresh Latchkey runner. Requires a jobs-enabled key and bills runner minutes.
Check job statustool
A CLI job's state and, once it finishes, the command's exit code.
Read job logstool
A CLI job's output from the start or its latest lines, so the agent reads the result of the command it ran or sees that a long job is still writing.
List jobstool
The workspace's jobs, newest first, or only the ones still queued or running, each with its state, elapsed time and cost so far.
Cancel a jobtool
End a job the agent started, at once if it is still waiting in the queue. Requires a jobs-enabled key.
Set a batch budgettool
Set or lower a budget for a batch of jobs. Once its jobs have cost that much at list rates, Latchkey starts no more of them. Requires a jobs-enabled key.
Fix a CI failureprompt
Drive a guided fix of a specific failure from inside your editor.
Triage CI failuresprompt
Survey what is failing across your monitored repositories and prioritize.
You never call these by name. You ask your agent a plain-language question, and it decides which capability answers it. Some illustrative pairings:
| You ask your agent | Capability it reaches for |
|---|---|
| "What is failing across our repos right now?" | Triage CI failures |
| "Show me the recent failed runs for this repo" | List failed runs |
| "Pull everything you have on that failed run" | Get failure bundle |
| "Fix the failing build" | Fix a CI failure |
| "Did that run pass? How long did each job take?" | Check run status |
| "Show me the end of the deploy job's log" | Tail run logs |
| "I pushed the fix, re-run CI and watch it" | Re-run a workflow |
| "Run the test suite on a clean Linux runner" | Run a one-off job |
| "Is that job done? What did it print?" | Check job status and Read job logs |
| "What is still running?" | List jobs |
| "Give this batch of jobs a $5 budget" | Set a batch budget |
What a session looks like
Two illustrative sessions. The exact wording, and the agent's exact replies, will vary by agent; the shape of the exchange is the point.
You open your editor and ask: "What is failing in our repos?" The agent runs the Triage CI failures flow and comes back with a survey of failures across your monitored repositories, prioritized. You narrow it: "Which of those matter most for the release?" and the agent reasons over the same data without you ever opening a CI tab.
The value is the loop staying in one place: question, context, next question, all inside the editor session where you will make the fix.
You ask: "Pull the failure bundle for the latest red build and fix it." The agent lists recent failed runs to find the right one, pulls the full bundle for it (logs, diagnosis, and workflow details), and then drives a guided fix from inside your editor, proposing changes for you to review.
Note what did not happen: the agent never touched Latchkey settings or GitHub through the key. It read failure context; the code changes went through you.
What is in a failure bundle
The failure bundle hands your agent what it would otherwise reconstruct by hand:
- The root cause, in plain language.
- The failing step's exit code and the exact source file where the error surfaced.
- The full captured logs of the failing step, including output GitHub hides in its log viewer; very large logs keep their final portion and say so. Secrets are stripped before the logs leave Latchkey.
- What self-healing already investigated and why it stood down, plus the workflow definition.
Setup
01
Create an API key
Open Settings, API keys and agents (owners and admins manage keys). Click Generate key, name it after where it will live (for example "Cursor on my laptop"), and pick an expiry: Never (the default), 30 days, 60 days, 90 days, or 1 year. Tick the capabilities the key needs (workflow dispatch, reading CLI job status and logs, running CLI jobs); capabilities are fixed at creation.
02
Copy the key immediately
The full key (it starts with lk_live_) is shown once, at creation. After that the UI only shows a placeholder. Treat it like a password; if you lose it, revoke it and create a new one.
03
Connect your agent
The Connect your agent block on the same settings tab shows the exact command for your workspace. For Claude Code it looks like:
terminal
1claude mcp add --transport http latchkey \
04
Use it
Ask your agent about failing CI ("what is failing in our repos?", "pull the failure bundle for the latest red build and fix it"). Any MCP-compatible client that supports HTTP transport with a bearer header works the same way.
Re-run workflows after a fix (opt-in)
By default a key is read-only. If you want the loop to close (agent fixes the code, pushes, re-runs CI, and watches it go green), create a key with Allow workflow dispatch checked. That key additionally carries the mcp:dispatch scope, and your agent can then trigger workflow_dispatch runs in your monitored repositories, poll them with the run-status tool when their jobs run on Latchkey runners, and read their logs when they finish. Green runs are readable too, so the agent can confirm the fix, not just observe the failure.
- Dispatch works only on repositories your workspace monitors, and only for workflows that declare the
workflow_dispatchtrigger. - Existing keys never gain dispatch retroactively; mint a new key with the checkbox enabled.
- The re-run runs whatever is on the branch you dispatch against; push the fix first, then dispatch.
Run jobs on fresh runners (opt-in)
The second opt-in write is running one-off jobs. A key created with Allow running CLI jobs (includes reading) carries the jobs:run scope (jobs:read, for status and logs, comes with it), and your agent can then use the Run a one-off job tool: one shell command on a fresh, isolated Latchkey runner, billed as ordinary runner minutes from the same free-minute pool as your workflows. The runner starts clean, with no repository contents; jobs that need your working tree go through the Latchkey CLI, which packs and uploads it. Allow reading CLI job status and logs is the narrower grant (jobs:read alone) for a key that should follow jobs but never start them.
- Jobs default to a 30 minute timeout, configurable up to 3 hours, and the agent picks a runner size (
smallwhen it does not). - A jobs-enabled key spends money: every job bills at the runner's standard per-minute rate. Name the key for the agent that holds it and give it an expiry.
- Cancel a job with the Cancel a job tool or
latchkey cancel, which need thejobs:runscope, or with Cancel job on its row under Running now on the Runs page.
acme-api · zsh · latchkey run
In a terminal in ~/acme-api, a coding agent runs latchkey run 'npm test'. The CLI packs and uploads the working tree and the job's log streams back: state: running, then vitest. src/billing/invoice.test.ts passes. In src/auth/refresh.test.ts the test keeps a token with an hour left fails with AssertionError: expected true to be false // Object.is equality, and the summary reads 1 failed and 411 passed of 412 tests. The CLI prints state: failed and Job cli-3a7f1e92-6c4b-4d18-8e5a-2b9c0d7f4a16 failed (exit 1). The agent types the comment # fix: convert expires_at from seconds to ms in src/auth/refresh.ts, then runs latchkey run 'npm test' again. The new job packs the edited tree the same way, src/auth/refresh.test.ts passes, all 412 tests in 38 files pass, and the CLI prints state: succeeded and Job cli-9e04b6d3-1f7a-4c2e-b5d8-6a3f0e1c7b29 succeeded (exit 0).
FIG. 2.6-B An agent drives latchkey run like any shell command: the failing test is already in the stream it reads, and the exit code, 1 then 0, is the verdict. Every run packs the working tree again, so the fix reaches the next job without a commit or a push.
Security model
- Read-only by default. Keys can read CI failure and run data; changing anything in Latchkey or GitHub is off by default. The writes a key can opt into at creation are workflow dispatch (
mcp:dispatch), running jobs on Latchkey runners (jobs:run) and setting workspace secrets (secrets:write). A secrets key can set or replace a secret but never read one back, and no key reaches any other Latchkey setting or arbitrary GitHub actions. - Workspace-scoped. The workspace is derived from the key itself, so a key can only ever see its own workspace's data.
- Revocable. Revoke any key from Settings, API keys and agents: a write-capable key (dispatch, jobs or secrets) loses access immediately, a read-only key within about a minute. Revoked keys stay listed under a "Revoked (n)" section for audit.
What those three properties mean in practice. Read-only-by-default bounds the blast radius of a leak: a stolen default key exposes CI failure data (including log excerpts), which is why you should still protect it, but it cannot open PRs, alter settings, or act on GitHub on your behalf. A stolen dispatch-enabled key can additionally trigger dispatchable workflows in your monitored repositories, a stolen jobs-enabled key can run commands on billable runners in your workspace, and a stolen secrets-enabled key can set or replace any secret your jobs read (though it can never read one back), which is exactly why each write is a per-key opt-in with a warning at creation, not a default. Workspace scoping means there is nothing to configure and nothing to get wrong: the key itself determines what it can see, and it can never see another workspace. And because revocation is fast and revoked keys stay listed for audit, the safe response to any doubt is simply to revoke and reissue.
Two low-effort habits that keep this clean: create a separate key for each tool or machine (the naming prompt at creation, like "Cursor on my laptop", exists exactly for this), so revoking one key never breaks the others; and pick the shortest expiry that fits how you work, reserving never for setups you actively track. Key management lives with owners and admins; see Team and roles and Security and permissions for the wider model.
Latchkey also publishes machine-readable descriptors so an agent can discover the surface without being told. The REST Jobs API is served from https://api.latchkey.dev and is fully described by an OpenAPI 3.1 specification; the MCP server has its own manifest listing every tool and the scope it needs.
| File | What it is |
|---|---|
| /openapi.json | OpenAPI 3.1 contract for the Jobs API: operations, typed schemas, scopes and error shapes. |
| /.well-known/mcp/manifest.json | MCP server descriptor: transport, auth, and all eleven tools with their scopes. |
| /agent.txt | Short plain-text brief on when to reach for Latchkey and how to call it. |
| /llms.txt | Index of the site and its content, with a when-to-use section. |
Every content page on the site also has a markdown twin at the same URL plus .md, linked from the page head as a rel="alternate" link. It carries the same content without the page markup, which is far cheaper for an agent to read.
Q.01What can a connected AI agent actually do?
Triage failures, pull failure bundles, check run status, tail logs, drive fixes from your editor and run one-off jobs on fresh runners. Any MCP client works, including Claude Code and Cursor, against Latchkey's MCP server at https://latchkey.dev/mcp.
Q.02Are API keys read-only?
By default, yes. Keys are workspace-scoped, shown once at creation and revocable at any time. Re-running workflows, reading CLI job status and logs, and running jobs are each a separate explicit opt-in chosen when the key is created, so nothing gains write access by accident.
Q.03How do I hand a specific finding to my agent?
From the AI Insight page. Copy prompt puts the finding and its context on your clipboard in a form an agent can act on, and a Set up MCP shortcut is offered if no key exists yet, so you do not have to reconstruct the problem by hand.