Conversation
Fm/firstmate forgejo pr support
* feat(bin): add deterministic agent lifecycle control Separate firstmate's data plane from its control plane. bin/fm-send.sh is the data plane: conversational text, always routing-marked for a kind=secondmate target. That marking is right for a message and wrong for a lifecycle command - a marked "/quit" arrives as ordinary chat the agent reasons about instead of executing. bin/fm-control.sh is the control plane: allowlisted interrupt, exit, and transactional relaunch verbs addressed to an exact task id, with per-harness mechanics owned by the executable bin/fm-control-lib.sh rather than improvised in agent prose, and a verified postcondition for every action. There is no arbitrary-text and no raw-key entry point. relaunch runs as a transaction with a durable journal: it resolves the profile, proves the work it must preserve is recoverable, records the required progress note, stops the old agent, then delegates the launch to its single owner, bin/fm-spawn.sh --relaunch, which adopts the recorded endpoint and worktree instead of creating either. A refusal before the stop leaves the record and instructions byte-identical; a failure after it reports the concrete state rather than claiming an agent that is not running. Teardown and discard stay separate and explicit. exit and relaunch require a backend with a recovery-grade agent-state classifier, so zellij, orca, and cmux are refused rather than reported as successful blind. A remotely placed secondmate is refused by name, because its agent runs on a host where none of these postconditions can be read. * fix(control): resolve a recorded harness to its adapter before retiring wiring fm-spawn arms per-task harness wiring on prefixes, because a task launched from a raw command records that command's basename rather than the exact adapter name. The control plane's retirement tables are keyed by the exact adapter, so a task recorded as `grok-2` had its turn-end token, private registry entry, and worktree hook pointer armed and never retired - leaving a registry entry that outlived the agent that owned it. State the prefix rule once, in the capability owner, and resolve the recorded value through it before every table lookup. bin/fm-send.sh's composer-clear lookup reads the same owner instead of keeping its own copy of which adapters need one. * test(control): pin muse session-binding retirement across a harness switch * no-mistakes(review): Resolve prefixed harnesses across lifecycle control verbs * no-mistakes(review): Report interrupt delivery without fabricating cancellation state * no-mistakes(review): Clear disabled relaunch trace context atomically * no-mistakes(review): Clarify control interrupts and restore legacy send state * no-mistakes(review): Refuse ambiguous relaunches and report exit delivery * no-mistakes(review): Revalidate interrupts and accept interrupt-stopped exits * no-mistakes(review): Lock descendant tasks before forced recursive teardown * no-mistakes(document): Align lifecycle adapter documentation with control plane * no-mistakes: apply CI fixes * fix(bin): serialize fresh task publication with forced teardown Forced secondmate teardown enumerated a home's task set, locked what it found, then re-enumerated while removing. A fresh spawn takes only its own per-task lock, so a record published inside that window was invisible to the preflight and visible to the cleanup: it was destructively processed while never lifecycle-locked. Reproduced with real agents. A record published 0.249s after teardown began was removed, its window closed, and its worktree returned to the pool - while both commands reported success. A per-task lock cannot protect a task that does not exist yet. Add a per-home task-set lock guarding WHICH tasks a home has, as opposed to the metadata lock guarding one task's record. Teardown takes it per home, parent before child, before enumerating and holds it through cleanup. A fresh spawn takes it before its own per-task locks and holds it through publication; a relaunch is exempt, because it republishes an existing task already covered by that task's control lock. Either the spawn publishes first and the teardown's preflight covers it, or the teardown owns the set and the spawn refuses. Both directions fail closed, and both are pinned by tests that hold the lock rather than racing on timing. * no-mistakes(review): Serialize remote secondmate publication with forced teardown * no-mistakes(review): Preserve remote spawn routing and state initialization * no-mistakes(review): Serialize teardown when descendant state is absent * no-mistakes(review): Cover symlinked descendant state refusal * no-mistakes(document): Document task-set serialization safeguards * no-mistakes(lint): Isolate task-set lock path resolution * no-mistakes: apply CI fixes
* feat(stow): tiered decaying memory with captain-gated offload to local excluded skills Implement the captain-adopted /stow redesign from the v2 tiering report as amended by the adoption decision: - Per-entry trailing HTML-comment markers with three tiers named for their handling: pinned (no clock, no eviction), aging (stale after 30 days), perishable (stale after 7 days, mandatory checkable expiry condition). - File-scoped defaults (captain.md and captain-shared.md pinned, learnings.md aging) with a self-describing legend line per file header. - Reinforcement requires session evidence; re-reading memory never counts. - Archive-not-delete: stale and budget-evicted entries move with provenance to the never-injected data/memory-archive.md; prune always means the cold tier, and a stale unique fact is never deleted. - Captain-gated over-budget offload: staleness evaluated before scope, the sweep runs only when still over budget after decay and consolidation, proposals go through the receipt plus one durable captain-held backlog item, migration runs through the destination's normal path, and the memory entry leaves only once the destination is live. - Offload destination per the adoption decision: a user-owned skill under .agents/skills/<freeform-name>/ excluded via the local .git/info/exclude, with the hard rule that stow never creates or writes a tracked skill. - Five graduation moves, receipt verbs archived and proposed-offload, and the one-time non-destructive migration of unmarked legacy entries. The public skills/stow/SKILL.md mirrors the generic parts (markers, decay, archive exit, user-approved on-demand offload exit, migration) with no firstmate-specific paths. The load-bearing assumption that a git-excluded skill is still discovered was verified empirically against Claude Code 2.1.226 (direct .git/info/exclude scratch-repo test plus an in-repo ignored-probe test); the dated evidence is recorded in docs/verification/stow-memory.md. The graduation list's deletion move is deliberately narrowed to duplicates already preserved by a stronger owner, reconciling the v2 report's retained 'deletion of a stale entry' wording with its own prune-always-archives rule. * no-mistakes(review): Persist legacy migration grace across stow passes * no-mistakes(review): Enforce archival invariants and exempt default-pinned legacy entries * no-mistakes(review): Clarify offload scope, archive placement, and marker boundaries * no-mistakes(review): Enforce aging fallback and verify excluded skill loading * no-mistakes(review): Fix stow decay, pinned offload, and archival safeguards * no-mistakes(review): Preserve pinned entries, approvals, and archive provenance * no-mistakes(review): Restrict stow mutations to editable memory files * no-mistakes(review): Clarify skill destinations, collision checks, and migration legends * no-mistakes(review): Resolve exclude paths for linked worktrees * no-mistakes(review): Secure per-home excluded skill migration * no-mistakes(test): Require explicit tier markers on new stow entries * no-mistakes(test): Route missing shared legends to primary owner * no-mistakes(document): Align stow documentation with tiered memory * fix(stow): converge the pass on an over-budget home (dogfood D1-D3) The dogfood run against a copy of the real over-budget home showed the pass increasing the deficit from 624 to 1,107 estimated tokens and the relief ladder provably unable to reach budget. Three skill-text fixes: - D1: markers become single-token spellings (<!--a:DATE-->, <!--p:DATE-->, <!--P-->, <!--g-->), entries matching a pinned file default carry no marker, the per-file policy legend collapses to a one-line pointer naming the stow skill as the scheme owner, and marker/pointer bytes are explicitly counted content - roughly 76% less metadata cost on the dogfooded home's first installment. - D2: the eviction rung gains a convergence precondition - total the eligible pool first, and when archiving all of it cannot reach budget, skip eviction entirely, archive nothing for budget reasons, and report the exempt pinned floor as the concrete inability in the final step. - D3: budget eviction considers only dated aging entries; <!--g--> legacy-grace entries are ineligible until their grace cycle resolves, so eviction cannot cancel promised grace or invert against validation. Public skill mirrors the D1 marker/pointer changes; D2/D3 are internal because the public skill has no budget ladder. * no-mistakes(test): Enforce evidence-only reinforcement during stow migration * no-mistakes(document): Clarify stow receipt marker actions
fix(dispatch): forward max effort to Codex
…rchalycious issue keys
…down delivery guards
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Intent
Implement two permanent Firstmate delivery safeguards.
First, no-mistakes completion means the full delivery contract, never merely a clean implementation commit or a worker-written
done:line.A worker begins the required no-mistakes flow immediately after implementation, commit-only status never reconciles as completed, checks-passed remains PR-ready rather than merged completion, and backlog completion stays downstream of guarded delivery.
Direct-PR and local-only semantics remain unchanged.
Second, enforce task-declared issue title and link requirements before a PR is registered or merged.
Carry the expected issue key and title/link rules explicitly from task intake through the generated brief and durable metadata, use one shared provider-validation seam, reject missing or mismatched provider fields before publishing PR metadata or arming merge monitoring, and keep diagnostics free of provider-controlled shell syntax.
The validation contract is generic task metadata and does not hard-code a tracker or project.
Keep tasks-axi as bookkeeping rather than delivery authority, avoid a general project-policy language, and preserve unrelated provider behavior.
What Changed
done:events cannot complete tasks, checks-passed remains PR-ready, and guarded merge or teardown gates backlog completion.Risk Assessment
Medium.
The change spans lifecycle reconciliation, provider validation, migration, teardown, and generated worker instructions.
Testing