Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
9f22ebf
feat: support devin harness
codeatspeed Jul 13, 2026
7dc5e35
no-mistakes(review): Captain, preserve Devin repository config when a…
codeatspeed Jul 14, 2026
668971b
no-mistakes(review): Captain, remove jq dependency from Devin config …
codeatspeed Jul 14, 2026
591478a
no-mistakes(review): Captain, preserve recoverability for invalid Dev…
codeatspeed Jul 14, 2026
ccc2390
no-mistakes(review): Captain, harden Devin config merging and harness…
codeatspeed Jul 14, 2026
0e1ea2d
no-mistakes(test): Captain, stabilize bootstrap and shellcheck tests
codeatspeed Jul 14, 2026
339b9b6
no-mistakes(test): Captain, skip Herdr E2E when default session is un…
codeatspeed Jul 14, 2026
d8712cb
no-mistakes(document): Captain, synchronize Devin harness documentation
codeatspeed Jul 14, 2026
4a8bab6
no-mistakes(lint): Captain, split local declarations from assignments
codeatspeed Jul 14, 2026
4f68c24
no-mistakes(review): Captain, preserve Devin config layering
codeatspeed Jul 14, 2026
8efffd5
no-mistakes(review): Captain, align Devin checkpoint override rendering
codeatspeed Jul 14, 2026
a27ee35
no-mistakes(test): Captain, preserve Herdr lab failure status
codeatspeed Jul 14, 2026
64fe806
no-mistakes(test): Captain, release watcher lock on checkpoint timeout
codeatspeed Jul 14, 2026
3acf333
no-mistakes(document): Document Devin harness coverage
codeatspeed Jul 14, 2026
d06e6cf
no-mistakes(review): Captain, tighten Devin lock-holder detection
codeatspeed Jul 14, 2026
9210b5d
no-mistakes(review): Captain, centralize strict harness process detec…
codeatspeed Jul 14, 2026
de7c843
no-mistakes(document): Document exact harness liveness classification
codeatspeed Jul 14, 2026
4988440
no-mistakes(document): Document Devin harness integration
codeatspeed Jul 15, 2026
af2cf6e
no-mistakes(review): Captain, fix Devin harness integration regressions
codeatspeed Jul 28, 2026
4ed5d23
no-mistakes(review): Captain, remove duplicate contract and fix sessi…
codeatspeed Jul 28, 2026
7c4bff5
no-mistakes(review): Captain, consolidate Devin contracts and remove …
codeatspeed Jul 28, 2026
e57addb
no-mistakes(document): Synchronize Devin harness documentation, captain
codeatspeed Jul 28, 2026
69f6509
no-mistakes(lint): Captain, remove duplicate supervision harness lint…
codeatspeed Jul 28, 2026
cbb3ee4
fix(test): repair Devin CI regressions
codeatspeed Jul 29, 2026
1acea42
no-mistakes(review): Guard absent-default Herdr lifecycle without skips
codeatspeed Jul 29, 2026
70865dd
no-mistakes(document): Correct Devin documentation ownership and stal…
codeatspeed Jul 29, 2026
c290893
no-mistakes(document): Document Devin backend cleanup support
codeatspeed Jul 30, 2026
383391d
fix: harden Devin config and hooks
codeatspeed Jul 30, 2026
18c63b5
no-mistakes(document): Document Devin hook roots and JSONC support
codeatspeed Jul 30, 2026
8f24e3c
no-mistakes(review): Add Devin SessionStart hook and control-safe JSO…
codeatspeed Jul 31, 2026
f846980
no-mistakes(review): Record Devin SessionStart as unverified on CLI 3…
codeatspeed Jul 31, 2026
f324572
no-mistakes(review): Remove Devin user state and document unverified …
codeatspeed Jul 31, 2026
5c8412a
no-mistakes(document): Document Devin harness review gaps
codeatspeed Jul 31, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .agents/skills/afk/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ The daemon constructs every current injection as the `away-supervisor` kind owne
The bare `FM_INJECT_MARK` form remains accepted for legacy daemon escalations during rollout.
U+2063 has no normal keyboard keystroke and survives terminal transport as UTF-8 text.
This is how firstmate tells a daemon escalation apart from a real message in the same pane.
The operational prefix travels with the message text; it does not rely on harness-level typed-vs-injected detection, which is not portable across claude, codex, opencode, pi, pi-signed, grok, and kimi.
The operational prefix travels with the message text; it does not rely on harness-level typed-vs-injected detection, which is not portable across claude, codex, opencode, pi, pi-signed, grok, kimi, and devin.

## Busy-guard and composer guard

Expand Down
2 changes: 1 addition & 1 deletion .agents/skills/firstmate-orca/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ It does not replace `AGENTS.md`, `docs/orca-backend.md`, or `harness-adapters`.

Orca is a runtime backend, not an agent harness.
The runtime backend owns the task endpoint and, for Orca, the task worktree.
The harness is the agent process launched inside that endpoint, such as `claude`, `codex`, `opencode`, `pi`, `pi-signed`, `grok`, or `kimi`.
The harness is the agent process launched inside that endpoint, such as `claude`, `codex`, `opencode`, `pi`, `pi-signed`, `grok`, `kimi`, or `devin`.
Load `harness-adapters` for harness-specific launch, interrupt, resume, trust-dialog, and skill-invocation facts.

Implementation details, metadata fields, teardown guarantees, and limitations live in `docs/orca-backend.md`.
Expand Down
44 changes: 39 additions & 5 deletions .agents/skills/harness-adapters/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: harness-adapters
description: Agent-only reference for firstmate harness operations. Use before spawning or recovering a crewmate or secondmate, handling a trust dialog, sending a harness-specific skill invocation, interrupting or exiting an agent, resuming an exited agent, or verifying a new harness adapter. Contains verified facts for claude, codex, opencode, pi, pi-signed, grok, and kimi.
description: Agent-only reference for firstmate harness operations. Use before spawning or recovering a crewmate or secondmate, handling a trust dialog, sending a harness-specific skill invocation, interrupting or exiting an agent, resuming an exited agent, or verifying a new harness adapter. Contains verified facts for claude, codex, opencode, pi, pi-signed, grok, kimi, and devin.
user-invocable: false
metadata:
internal: true
Expand Down Expand Up @@ -53,8 +53,8 @@ Use that value for interrupt, exit, resume, and skill-invocation facts.

## Primary turn-end guard

The primary integrations for `claude`, `codex`, `opencode`, `pi`, `pi-signed`, and `grok` have empirically validated hook paths for the "no turn ends blind" guard.
`claude` and `codex` block directly through Stop hooks that preserve exit status 2 and stderr from `bin/fm-turnend-guard.sh`.
The primary integrations for `claude`, `codex`, `opencode`, `pi`, `pi-signed`, `grok`, and `devin` have empirically validated hook paths for the "no turn ends blind" guard.
`claude`, `codex`, and `devin` block directly through Stop hooks that preserve exit status 2 and stderr from `bin/fm-turnend-guard.sh`.
`opencode`, `pi`, and `pi-signed` expose passive lifecycle callbacks and force one bounded follow-up when the shared predicate blocks.
Grok selects native blocking or its pre-native bounded resume fallback from the exact running Stop payload; [`docs/turnend-guard.md`](../../../docs/turnend-guard.md) owns that contract.
Kimi is outside the primary turn-end guard scope, while `docs/turnend-guard.md` owns its separate guarded global hook for crew wake signals.
Expand All @@ -64,8 +64,8 @@ When changing any primary turn-end hook, validate the real harness behavior in a

## Primary pre-arm (PreToolUse) seatbelt

The primary integrations for `claude`, `codex`, `opencode`, `pi`, `pi-signed`, and `grok` also have wired PreToolUse-equivalent hooks that deny a watcher-arm anti-pattern (shell `&`, truncating pipe, bundling, broad `pkill -f fm-watch`) before it runs.
`claude` and `codex` block directly through PreToolUse hooks; `grok` blocks the same way but requires every `$VAR` reference in its hook `command` string to carry an inline `:-default` or it fails to launch the hook entirely.
The primary integrations for `claude`, `codex`, `opencode`, `pi`, `pi-signed`, `grok`, and `devin` also have wired PreToolUse-equivalent hooks that deny a watcher-arm anti-pattern (shell `&`, truncating pipe, bundling, broad `pkill -f fm-watch`) before it runs.
`claude`, `codex`, and `devin` block directly through PreToolUse hooks; `grok` blocks the same way but requires every `$VAR` reference in its hook `command` string to carry an inline `:-default` or it fails to launch the hook entirely.
`opencode`, `pi`, and `pi-signed` block by throwing from `tool.execute.before` / returning `{block: true}` from `tool_call`.
The exact hook files, commands, output-shaping quirks (Claude Code only honors the deny when stdout is empty), and validation transcripts are owned by `docs/arm-pretool-check.md`.
When changing any watcher-arm PreToolUse hook, validate the real harness behavior in a scratch project before trusting it, then update that doc.
Expand Down Expand Up @@ -93,6 +93,7 @@ Full mechanics, scoping, and fail-open behavior live in `docs/sessionstart-nudge
- `opencode`: verified on 1.17.18; `session.created` plus `client.session.promptAsync` starts the nudge turn in the TUI, while `opencode run` remains fail-open headless.
- `pi` and `pi-signed`: verified native `session_start`; the existing primary extension handles `startup`, `new`, and `resume` and uses `pi.sendMessage` to inject context without racing a positional launch prompt.
- `grok`: the 0.2.103 project `SessionStart` event fires with `source=new`, but stdout does not reach model context; the tracked project hook remains fail-open, and a global token-guarded fallback requires a captain decision.
- `devin`: Devin CLI 3000.3.22 did not deliver a unique tracked `SessionStart` `add_context` probe to model context; keep the tracked hook configured, but treat native session-start delivery as unverified until a CLI version implements it.

## Primary watcher supervision

Expand Down Expand Up @@ -127,6 +128,7 @@ The supported launch-profile flags below are verified locally; each row records
| pi / pi-signed | `--model <model>` | `--thinking <low\|medium\|high\|xhigh\|max>` | Verified 2026-07-27 on Pi and pi-signed 0.82.0. Both expose the same accepted thinking levels and completed the same model-qualified max-thinking smoke. |
| opencode | `--model <provider/model>` | none for firstmate's interactive launch | Verified on opencode 1.17.6. `opencode run` has `--variant`, but firstmate launches the interactive `opencode --prompt` path, which has no verified effort flag. |
| kimi | `--model <model>` | none | Verified 2026-07-25 on Kimi Code CLI 0.29.1. |
| devin | `--model <model>` | none | Verified on Devin CLI 3000.1.27. The interactive CLI exposes no effort flag. |

The concrete `harness` field owns adapter identity independently of the model provider: `harness=pi` with `model=xai/grok-*` is Pi using xAI, not `harness=grok`, and does not require Grok CLI login; `harness=grok` remains the standalone Grok Build CLI adapter.
`bin/fm-auth-preflight.sh` enforces that split deterministically, resolving a tuple's authentication surface from quota-axi's emitted auth sources rather than from a harness or model name; use it instead of reasoning about which credential store a tuple reads.
Expand Down Expand Up @@ -162,13 +164,45 @@ Natural language is acceptable if uncertain.
- pi and pi-signed: no separate verified skill invocation beyond normal command behavior; use natural language if the exact skill command is uncertain.
- grok: `/<skill>`, for example `/no-mistakes` (same form as claude). Verified end to end: grok discovers the user-level `no-mistakes` skill, `/no-mistakes` invokes it, and grok drives a real `no-mistakes axi run`. Like codex's `$`/`/` popups, typing `/<skill>` opens grok's slash-autocomplete, so a too-fast Enter selects the popup entry instead of sending, and for an argument-taking command (like `/no-mistakes`'s optional task-first argument) that first Enter only expands the popup selection into an argument-hint placeholder rather than submitting - a genuine second Enter is required (see the grok section below for the 2026-07-03 incident and fix). `fm_tmux_submit_core`'s retried Enter (used by `fm-send` on the tmux backend) handles this through the structural composer reader; the herdr backend needed a dedicated fix (`fm_backend_herdr_composer_state`, docs/herdr-backend.md) because its prior delta-based verification false-positived on that same popup-close content change.
- kimi: `/<skill>`, for example `/no-mistakes`.
- devin: `/<skill>`. Devin CLI exposes skills as slash commands and discovers repository skills under `.devin/skills/`; use natural language if a specific installed skill is not listed.

## Submission acknowledgement hazards

A send or key action reporting success is not proof that the intended action happened.
OpenCode can accept and queue an Enter while leaving text visible, Grok can consume Enter in its slash popup without submitting, and Kimi can silently drop a message sent before readiness even though the send returns success.
The shared symptom is a healthy-looking pane with no work in progress, so each adapter must verify the observable postcondition that is specific to its TUI.

## devin (VERIFIED 2026-07-13, Devin CLI 3000.1.27)

| Fact | Value |
|---|---|
| Busy-pane signature | `esc to interrupt` |
| Exit command | `/exit` |
| Interrupt | single Escape |
| Skill invocation | `/<skill>` |
| Autonomy | `--permission-mode dangerous` |
| Process name | `devin` |
| Resume | `devin --resume <session-id>` or `devin --continue` |

Launch with `DEVIN_CLI=1 devin --permission-mode dangerous --respect-workspace-trust true --prompt-file <brief>`.
Firstmate-launched crewmates add `--config <state-owned-config>` containing the native user configuration plus their task Stop hook, without overwriting the user's file.
The native user configuration accepts Devin's supported JSONC syntax, including line comments, block comments, trailing commas, and comment-like string content; Firstmate still requires the config root, `read_config_from`, `hooks`, and `hooks.Stop` values to have their documented object or array shapes before composing the state-owned copy.
That state-owned config disables Claude compatibility import so Devin has exactly one harness-owned Stop path.
Devin loads the repository configuration through its native project layer alongside that override, so project settings and hooks are not copied or applied twice.
Secondmates omit that override and load the tracked primary hooks from their Firstmate home.

Devin automatically loads repository `.devin/config.json`.
Its shell tool is named `exec`, and the `PreToolUse` payload carries the exact command at `.tool_input.command`.
Its native `Stop` hook fires at every completed turn and accepts the Claude-compatible command-hook schema.
The tracked primary adapter uses direct blocking hooks for the watcher-arm seatbelt, cd guard, and turn-end guard.

The primary supervision protocol uses bounded foreground checkpoints.
No Devin background-task completion auto-wake contract has been verified, so do not substitute Claude or Grok background-notify supervision.

The first launch may print the logged-in account and organization before the TUI.
For a primary session launched normally, approve the workspace-trust prompt once per clone so repository hooks load.
Firstmate keeps workspace trust enabled and relies on Devin's persisted once-per-worktree approval instead of bypassing that gate.

## claude (VERIFIED; busy-state hooks live-verified 2026-07-28 on Claude Code 2.1.220)

| Fact | Value |
Expand Down
43 changes: 43 additions & 0 deletions .devin/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"version": 1,
"read_config_from": {
"claude": false
},
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "bash -lc 'root=${DEVIN_PROJECT_DIR:-}; if [ -z \"$root\" ]; then root=$(git rev-parse --show-toplevel 2>/dev/null) || exit 0; fi; [ -f \"$root/.devin/config.json\" ] && [ -x \"$root/bin/fm-sessionstart-nudge.sh\" ] || exit 0; nudge=$(\"$root/bin/fm-sessionstart-nudge.sh\") || exit 0; [ -n \"$nudge\" ] || exit 0; node -e \"process.stdout.write(JSON.stringify({add_context: process.argv[1]}))\" \"$nudge\"'"
}
]
}
],
"PreToolUse": [
{
"matcher": "exec",
"hooks": [
{
"type": "command",
"command": "bash -lc 'root=${DEVIN_PROJECT_DIR:-}; if [ -z \"$root\" ]; then root=$(git rev-parse --show-toplevel 2>/dev/null) || exit 0; fi; [ -f \"$root/.devin/config.json\" ] && [ -x \"$root/bin/fm-arm-pretool-check.sh\" ] || exit 0; exec \"$root/bin/fm-arm-pretool-check.sh\" --claude'"
},
{
"type": "command",
"command": "bash -lc 'root=${DEVIN_PROJECT_DIR:-}; if [ -z \"$root\" ]; then root=$(git rev-parse --show-toplevel 2>/dev/null) || exit 0; fi; [ -f \"$root/.devin/config.json\" ] && [ -x \"$root/bin/fm-cd-pretool-check.sh\" ] || exit 0; exec \"$root/bin/fm-cd-pretool-check.sh\" --claude'"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "bash -lc 'root=${DEVIN_PROJECT_DIR:-}; if [ -z \"$root\" ]; then root=$(git rev-parse --show-toplevel 2>/dev/null) || exit 0; fi; [ -f \"$root/.devin/config.json\" ] && [ -x \"$root/bin/fm-turnend-guard.sh\" ] || exit 0; exec \"$root/bin/fm-turnend-guard.sh\"'"
}
]
}
]
}
}
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ A silent bootstrap section needs no action; for any printed actionable diagnosti
## 4. Harness and runtime dispatch

Load `harness-adapters` before every spawn or recovery and before trust handling, skill invocation, interrupt, exit, resume, or adapter verification.
The verified harnesses are `claude`, `codex`, `opencode`, `pi`, `pi-signed`, `grok`, and `kimi`; never dispatch on an unverified adapter.
The verified harnesses are `claude`, `codex`, `opencode`, `pi`, `pi-signed`, `grok`, `kimi`, and `devin`; never dispatch on an unverified adapter.
If static `config/crew-harness` or `config/secondmate-harness` names an unverified adapter, report it and fall back only to a verified adapter rather than launching it.

`docs/configuration.md` owns dispatch-profile and runtime-backend schemas, `bin/fm-harness.sh` owns static resolution, and `bin/fm-spawn.sh` owns launch flags and fail-closed validation.
Expand Down
20 changes: 16 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ Full detail on every feature lives in [docs/architecture.md](docs/architecture.m

### Requirements

- A verified primary agent harness: Claude Code, Grok, Pi, `pi-signed`, Codex, or OpenCode.
- A verified primary agent harness: Claude Code, Grok, Pi, `pi-signed`, Codex, OpenCode, or Devin CLI.
- Git and the GitHub CLI, authenticated through `gh auth login`.
- The CLI and dependencies for your selected runtime backend; tmux is the reference default.

Expand All @@ -72,7 +72,7 @@ Claude Code uses a tracked Stop hook for tokenless watcher re-arm and rewake, Gr
All three have verified turn-end guard paths when launched with their documented setup.
Pick whichever one matches your subscription and workflow.

Codex and OpenCode are also verified and supported as primary harnesses; Codex uses bounded foreground checkpoints, and OpenCode uses a TUI plugin, so both carry more harness-specific supervision tradeoffs than the three co-primaries.
Codex, OpenCode, and Devin CLI are also verified and supported as primary harnesses; Codex and Devin use bounded foreground checkpoints, and OpenCode uses a TUI plugin, so all three carry more harness-specific supervision tradeoffs than the three co-primaries.

### Install and launch

Expand Down Expand Up @@ -111,6 +111,18 @@ The hidden operational inputs remain ordinary user-role messages with unchanged
The preference persists for the effective Firstmate home, and toggling it off restores ordinary rendering.
[Calm's current behavior and supported limits](docs/calm.md) are separate from its [version-scoped maintainer evidence](docs/calm-mode-feasibility.md).

The other verified primary harnesses launch normally from the repository root:

```sh
codex
opencode
devin
```

Install Devin CLI with Cognition's official installer when needed: `curl -fsSL https://cli.devin.ai/install.sh | bash`.
Approve Devin's workspace-trust prompt once per clone so it loads the tracked `.devin/config.json` safety hooks.
Devin uses bounded foreground supervision checkpoints.

### Talk to it

```sh
Expand Down Expand Up @@ -165,7 +177,7 @@ Full architecture - the supervision engine, worktree isolation, secondmates, dis
## Built-in skills

Firstmate ships these user-invocable built-in skills.
Claude and grok use the slash form shown here; codex uses the same names with `$`, such as `$afk`.
Claude, Grok, and Devin use the slash form shown here; Codex uses the same names with `$`, such as `$afk`.

| Skill | What it does |
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- |
Expand Down Expand Up @@ -210,7 +222,7 @@ Firstmate's skills live in two separate places with different audiences:
- [docs/gitlab-merge-watch.md](docs/gitlab-merge-watch.md) - maintainer verification for GitLab merge watching on arbitrary instances.
- [docs/turnend-guard.md](docs/turnend-guard.md) - the primary session's current "no turn ends blind" backstop, scope, loop safety, and compatibility limits.
- [docs/verification/supervision.md](docs/verification/supervision.md) - active maintainer verification for session-start, guard, continuity, and wedge integrations.
- [docs/supervision-protocols/](docs/supervision-protocols/) - rendered primary-harness watcher protocols for Claude, Codex, OpenCode, Pi and `pi-signed`, Grok, and unknown harness fallback.
- [docs/supervision-protocols/](docs/supervision-protocols/) - rendered primary-harness watcher protocols for Claude, Codex, Devin, OpenCode, Pi and `pi-signed`, Grok, and unknown harness fallback.
- [docs/scripts.md](docs/scripts.md) - the `bin/` toolbelt reference.
- [docs/documentation-audiences.md](docs/documentation-audiences.md) - documentation audiences and the machine-checked placement boundary.
- [`AGENTS.md`](AGENTS.md) - the distro's always-loaded operating contract and routing index for conditional procedures.
Expand Down
8 changes: 6 additions & 2 deletions bin/backends/tmux.sh
Original file line number Diff line number Diff line change
Expand Up @@ -192,11 +192,15 @@ fm_backend_tmux_agent_state() { # <target>
return 0
}
comm=${comm#-}
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
# shellcheck source=bin/fm-harness-process.sh
. "$script_dir/fm-harness-process.sh"
case "$comm" in
*claude*|*codex*|*opencode*|*grok*|*kimi*|pi|pi-signed|pi-launcher|Pi) printf 'alive' ;;
zsh|bash|sh|dash|ash|ksh|mksh|tcsh|csh|fish) printf 'dead' ;;
'') printf 'unreadable' ;;
*) printf 'ambiguous' ;;
*)
if fm_harness_process_name "$comm" '' >/dev/null; then printf 'alive'; else printf 'ambiguous'; fi
;;
esac
}

Expand Down
4 changes: 2 additions & 2 deletions bin/fm-arm-pretool-check.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
# bin/fm-arm-pretool-check.sh --command '<cmd>' [--background true|false]
#
# Stdin mode extracts .toolInput.command for Grok or .tool_input.command for
# Claude and Codex.
# Claude, Codex, and Devin.
# CLI mode is used by OpenCode and Pi after their adapters extract the exact
# command string.
# --background remains accepted for compatibility, but harness-native tracked
Expand Down Expand Up @@ -44,7 +44,7 @@ usage() {
Usage: fm-arm-pretool-check.sh [--command <cmd>] [--background true|false] [--claude]

With no --command, reads a PreToolUse-style JSON payload on stdin (Grok
toolInput.command, or Claude/Codex tool_input.command).
toolInput.command, or Claude/Codex/Devin tool_input.command).
Exits 0 to allow and 2 to deny.
The deny reason is written to stderr, with a Grok decision object on stdout
unless --claude is supplied.
Expand Down
Loading
Loading