Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
656a8f2
Hold, operator decisions and migration commands in the connector ledger
jorgemanrubia Sep 17, 2026
31ceb2a
Rename the operator tests' admit helper beside the dispatcher's
jorgemanrubia Sep 17, 2026
fe870c1
Add connect status, doctor, redispatch, discard, release, shadow prom…
jorgemanrubia Sep 17, 2026
47845a8
Test the operator commands
jorgemanrubia Sep 17, 2026
644faa8
Account for the operator commands in the smoke coverage
jorgemanrubia Sep 17, 2026
1abc245
Assert the dispatcher is offered nothing under the hold
jorgemanrubia Sep 17, 2026
9ab3bfa
Authorize a terminal move by a decision row; address the adversarial …
jorgemanrubia Sep 17, 2026
3f4847b
Test that only this record's own later discard lets it close
jorgemanrubia Sep 17, 2026
d7c1ba3
Recognize a finished promote by its decision, not the hold's cause
jorgemanrubia Sep 17, 2026
926e897
Keep a superseded task from taking follow-ups, and let an import with…
jorgemanrubia Sep 17, 2026
e579a83
Preallocate the crash table
jorgemanrubia Sep 17, 2026
eb99cc6
Rebase onto card 20's new head: one CheckPrivateFile, the dispatch to…
jorgemanrubia Sep 17, 2026
ce9f151
Close the second adversarial review: nothing asks for a decision alre…
jorgemanrubia Sep 17, 2026
7beaf99
Give the schema tamper in the migration test a context
jorgemanrubia Sep 17, 2026
c3d6fd8
Guard the migration with the instance lock, and refuse an edit that n…
jorgemanrubia Sep 17, 2026
40fc541
Close the fourth adversarial review: one lock for an import, a notice…
jorgemanrubia Sep 17, 2026
1c8cdb7
Return only an error from the refusal helpers, and mark the migrating…
jorgemanrubia Sep 17, 2026
0ed774e
Re-render a completion notice only when a person decided one of its e…
jorgemanrubia Sep 17, 2026
dd6dff6
Ask the driver's one-owner rule before acting on a recorded worker
jorgemanrubia Sep 17, 2026
e1dc6e5
Close the fifth adversarial review: say what became of a worker exactly
jorgemanrubia Sep 17, 2026
c87755f
Close the sixth review round: authorized blocked records are decided,…
jorgemanrubia Sep 17, 2026
93ab880
An authorization answers for the outcome it was made on
jorgemanrubia Sep 17, 2026
51a7517
Close an imported done outcome for good, and refuse a ledger a newer …
jorgemanrubia Sep 17, 2026
6fa6cf3
Refuse a newer ledger on the connector's own open, and record what an…
jorgemanrubia Sep 17, 2026
7f77956
Regenerate the CLI surface after the rebase
jorgemanrubia Sep 17, 2026
1d3cf55
Never date an authorization before the block it answers for
jorgemanrubia Sep 17, 2026
c8752cd
Teach the basecamp-connect skill the operator commands, and point a m…
jorgemanrubia Sep 17, 2026
b67dd55
Close review round ten: the skill and the command catalog match the c…
jorgemanrubia Sep 17, 2026
20025ad
Own the doctor's MCP server process outright, so its group is ended b…
jorgemanrubia Sep 17, 2026
4c5519c
Name the held state in the dispatch lifecycle test's exhaustive switch
jorgemanrubia Sep 17, 2026
c1b604d
Refuse a shadowing token before a redispatch touches the ledger, and …
jorgemanrubia Sep 17, 2026
93ed837
Say the pointer lines exist but are not this skill's yet, and label d…
jorgemanrubia Sep 17, 2026
e28c5cf
Speak the CLI's JSON in the decision commands, and say what the hold …
jorgemanrubia Sep 17, 2026
10468a7
Prove a discard withdraws a redispatch still waiting for its task
jorgemanrubia Sep 17, 2026
9a1e405
Assert the withdrawn authorization itself
jorgemanrubia Sep 17, 2026
7c66028
Report the task token's taker in status, as the worker is reported
jorgemanrubia Sep 17, 2026
fe11ddf
Keep the CLI building where the one-owner rule does not run
jorgemanrubia Sep 17, 2026
bda9d9e
Finish a canceled guard, and say what waits when the task was already…
jorgemanrubia Sep 17, 2026
75a4c23
Hand a worker nothing new under the hold, and say the lock file is on…
jorgemanrubia Sep 17, 2026
c02672a
Fail doctor for what the run command refuses: worktrees, and a platfo…
jorgemanrubia Sep 17, 2026
19ad2a4
Say what doctor does not write, and quote the profile in the command …
jorgemanrubia Sep 17, 2026
f67ec26
Validate a reconciliation wherever it comes from, and say what a pid …
jorgemanrubia Sep 17, 2026
62a2888
Silence contextcheck on the import validation subtests
jorgemanrubia Sep 17, 2026
e292e73
A hold is not a failed task, and a canceled guard is dated when it wa…
jorgemanrubia Sep 17, 2026
df2c4d6
Withhold, do not fail: the dispatcher reads a hold's refusal as a hold
jorgemanrubia Sep 17, 2026
4d91c1a
Take the connector's lock even when a promote has nothing left to move
jorgemanrubia Sep 17, 2026
29abedc
Say the retained worktrees are unavailable, not that there are none
jorgemanrubia Sep 17, 2026
aba1db5
Refuse the other first hand-off under the hold: a worker's first pull
jorgemanrubia Sep 17, 2026
a029c95
Merge remote-tracking branch 'origin/connect-outbox' into connect-ope…
jorgemanrubia Sep 18, 2026
1a3052a
Carry the operator commands onto the merged base
jorgemanrubia Sep 18, 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
189 changes: 189 additions & 0 deletions .surface
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ ARG basecamp config set 01 <value>
ARG basecamp config trust 00 [path]
ARG basecamp config unset 00 <key>
ARG basecamp config untrust 00 [path]
ARG basecamp connect discard 00 <event_id>
ARG basecamp connect import 00 <file>
ARG basecamp connect redispatch 00 <event_id>
ARG basecamp docs archive 00 <id|url>
ARG basecamp docs doc create 00 <title>
ARG basecamp docs doc create 01 [content]
Expand Down Expand Up @@ -669,8 +672,16 @@ CMD basecamp config trust
CMD basecamp config unset
CMD basecamp config untrust
CMD basecamp connect
CMD basecamp connect discard
CMD basecamp connect doctor
CMD basecamp connect import
CMD basecamp connect redispatch
CMD basecamp connect release
CMD basecamp connect setup
CMD basecamp connect shadow
CMD basecamp connect shadow promote
CMD basecamp connect show
CMD basecamp connect status
CMD basecamp docs
CMD basecamp docs archive
CMD basecamp docs doc
Expand Down Expand Up @@ -5351,6 +5362,7 @@ FLAG basecamp connect --count type=bool
FLAG basecamp connect --driver type=string
FLAG basecamp connect --help type=bool
FLAG basecamp connect --hints type=bool
FLAG basecamp connect --hold type=bool
FLAG basecamp connect --ids-only type=bool
FLAG basecamp connect --in type=string
FLAG basecamp connect --jq type=string
Expand All @@ -5368,6 +5380,111 @@ FLAG basecamp connect --stats type=bool
FLAG basecamp connect --styled type=bool
FLAG basecamp connect --todolist type=string
FLAG basecamp connect --verbose type=count
FLAG basecamp connect discard --account type=string
FLAG basecamp connect discard --agent type=bool
FLAG basecamp connect discard --cache-dir type=string
FLAG basecamp connect discard --count type=bool
FLAG basecamp connect discard --help type=bool
FLAG basecamp connect discard --hints type=bool
FLAG basecamp connect discard --ids-only type=bool
FLAG basecamp connect discard --in type=string
FLAG basecamp connect discard --jq type=string
FLAG basecamp connect discard --json type=bool
FLAG basecamp connect discard --markdown type=bool
FLAG basecamp connect discard --md type=bool
FLAG basecamp connect discard --no-hints type=bool
FLAG basecamp connect discard --no-stats type=bool
FLAG basecamp connect discard --profile type=string
FLAG basecamp connect discard --project type=string
FLAG basecamp connect discard --quiet type=bool
FLAG basecamp connect discard --stats type=bool
FLAG basecamp connect discard --styled type=bool
FLAG basecamp connect discard --todolist type=string
FLAG basecamp connect discard --verbose type=count
FLAG basecamp connect doctor --account type=string
FLAG basecamp connect doctor --agent type=bool
FLAG basecamp connect doctor --cache-dir type=string
FLAG basecamp connect doctor --count type=bool
FLAG basecamp connect doctor --help type=bool
FLAG basecamp connect doctor --hints type=bool
FLAG basecamp connect doctor --ids-only type=bool
FLAG basecamp connect doctor --in type=string
FLAG basecamp connect doctor --jq type=string
FLAG basecamp connect doctor --json type=bool
FLAG basecamp connect doctor --markdown type=bool
FLAG basecamp connect doctor --md type=bool
FLAG basecamp connect doctor --no-hints type=bool
FLAG basecamp connect doctor --no-stats type=bool
FLAG basecamp connect doctor --profile type=string
FLAG basecamp connect doctor --project type=string
FLAG basecamp connect doctor --quiet type=bool
FLAG basecamp connect doctor --stats type=bool
FLAG basecamp connect doctor --styled type=bool
FLAG basecamp connect doctor --todolist type=string
FLAG basecamp connect doctor --verbose type=count
FLAG basecamp connect import --account type=string
FLAG basecamp connect import --agent type=bool
FLAG basecamp connect import --cache-dir type=string
FLAG basecamp connect import --count type=bool
FLAG basecamp connect import --help type=bool
FLAG basecamp connect import --hints type=bool
FLAG basecamp connect import --ids-only type=bool
FLAG basecamp connect import --in type=string
FLAG basecamp connect import --jq type=string
FLAG basecamp connect import --json type=bool
FLAG basecamp connect import --markdown type=bool
FLAG basecamp connect import --md type=bool
FLAG basecamp connect import --no-hints type=bool
FLAG basecamp connect import --no-stats type=bool
FLAG basecamp connect import --profile type=string
FLAG basecamp connect import --project type=string
FLAG basecamp connect import --quiet type=bool
FLAG basecamp connect import --stats type=bool
FLAG basecamp connect import --styled type=bool
FLAG basecamp connect import --todolist type=string
FLAG basecamp connect import --verbose type=count
FLAG basecamp connect redispatch --account type=string
FLAG basecamp connect redispatch --agent type=bool
FLAG basecamp connect redispatch --cache-dir type=string
FLAG basecamp connect redispatch --count type=bool
FLAG basecamp connect redispatch --help type=bool
FLAG basecamp connect redispatch --hints type=bool
FLAG basecamp connect redispatch --ids-only type=bool
FLAG basecamp connect redispatch --in type=string
FLAG basecamp connect redispatch --jq type=string
FLAG basecamp connect redispatch --json type=bool
FLAG basecamp connect redispatch --markdown type=bool
FLAG basecamp connect redispatch --md type=bool
FLAG basecamp connect redispatch --no-hints type=bool
FLAG basecamp connect redispatch --no-stats type=bool
FLAG basecamp connect redispatch --profile type=string
FLAG basecamp connect redispatch --project type=string
FLAG basecamp connect redispatch --quiet type=bool
FLAG basecamp connect redispatch --stats type=bool
FLAG basecamp connect redispatch --styled type=bool
FLAG basecamp connect redispatch --todolist type=string
FLAG basecamp connect redispatch --verbose type=count
FLAG basecamp connect release --account type=string
FLAG basecamp connect release --agent type=bool
FLAG basecamp connect release --cache-dir type=string
FLAG basecamp connect release --count type=bool
FLAG basecamp connect release --help type=bool
FLAG basecamp connect release --hints type=bool
FLAG basecamp connect release --ids-only type=bool
FLAG basecamp connect release --in type=string
FLAG basecamp connect release --jq type=string
FLAG basecamp connect release --json type=bool
FLAG basecamp connect release --markdown type=bool
FLAG basecamp connect release --md type=bool
FLAG basecamp connect release --no-hints type=bool
FLAG basecamp connect release --no-stats type=bool
FLAG basecamp connect release --profile type=string
FLAG basecamp connect release --project type=string
FLAG basecamp connect release --quiet type=bool
FLAG basecamp connect release --stats type=bool
FLAG basecamp connect release --styled type=bool
FLAG basecamp connect release --todolist type=string
FLAG basecamp connect release --verbose type=count
FLAG basecamp connect setup --account type=string
FLAG basecamp connect setup --agent type=bool
FLAG basecamp connect setup --allow type=stringArray
Expand Down Expand Up @@ -5404,6 +5521,48 @@ FLAG basecamp connect setup --verbose type=count
FLAG basecamp connect setup --watch-completions type=stringArray
FLAG basecamp connect setup --worker type=string
FLAG basecamp connect setup --worktrees type=bool
FLAG basecamp connect shadow --account type=string
FLAG basecamp connect shadow --agent type=bool
FLAG basecamp connect shadow --cache-dir type=string
FLAG basecamp connect shadow --count type=bool
FLAG basecamp connect shadow --help type=bool
FLAG basecamp connect shadow --hints type=bool
FLAG basecamp connect shadow --ids-only type=bool
FLAG basecamp connect shadow --in type=string
FLAG basecamp connect shadow --jq type=string
FLAG basecamp connect shadow --json type=bool
FLAG basecamp connect shadow --markdown type=bool
FLAG basecamp connect shadow --md type=bool
FLAG basecamp connect shadow --no-hints type=bool
FLAG basecamp connect shadow --no-stats type=bool
FLAG basecamp connect shadow --profile type=string
FLAG basecamp connect shadow --project type=string
FLAG basecamp connect shadow --quiet type=bool
FLAG basecamp connect shadow --stats type=bool
FLAG basecamp connect shadow --styled type=bool
FLAG basecamp connect shadow --todolist type=string
FLAG basecamp connect shadow --verbose type=count
FLAG basecamp connect shadow promote --account type=string
FLAG basecamp connect shadow promote --agent type=bool
FLAG basecamp connect shadow promote --cache-dir type=string
FLAG basecamp connect shadow promote --count type=bool
FLAG basecamp connect shadow promote --help type=bool
FLAG basecamp connect shadow promote --hints type=bool
FLAG basecamp connect shadow promote --ids-only type=bool
FLAG basecamp connect shadow promote --in type=string
FLAG basecamp connect shadow promote --jq type=string
FLAG basecamp connect shadow promote --json type=bool
FLAG basecamp connect shadow promote --markdown type=bool
FLAG basecamp connect shadow promote --md type=bool
FLAG basecamp connect shadow promote --no-hints type=bool
FLAG basecamp connect shadow promote --no-stats type=bool
FLAG basecamp connect shadow promote --profile type=string
FLAG basecamp connect shadow promote --project type=string
FLAG basecamp connect shadow promote --quiet type=bool
FLAG basecamp connect shadow promote --stats type=bool
FLAG basecamp connect shadow promote --styled type=bool
FLAG basecamp connect shadow promote --todolist type=string
FLAG basecamp connect shadow promote --verbose type=count
FLAG basecamp connect show --account type=string
FLAG basecamp connect show --agent type=bool
FLAG basecamp connect show --cache-dir type=string
Expand All @@ -5425,6 +5584,28 @@ FLAG basecamp connect show --stats type=bool
FLAG basecamp connect show --styled type=bool
FLAG basecamp connect show --todolist type=string
FLAG basecamp connect show --verbose type=count
FLAG basecamp connect status --account type=string
FLAG basecamp connect status --agent type=bool
FLAG basecamp connect status --cache-dir type=string
FLAG basecamp connect status --count type=bool
FLAG basecamp connect status --help type=bool
FLAG basecamp connect status --hints type=bool
FLAG basecamp connect status --ids-only type=bool
FLAG basecamp connect status --in type=string
FLAG basecamp connect status --jq type=string
FLAG basecamp connect status --json type=bool
FLAG basecamp connect status --markdown type=bool
FLAG basecamp connect status --md type=bool
FLAG basecamp connect status --no-hints type=bool
FLAG basecamp connect status --no-stats type=bool
FLAG basecamp connect status --profile type=string
FLAG basecamp connect status --project type=string
FLAG basecamp connect status --quiet type=bool
FLAG basecamp connect status --shadow type=bool
FLAG basecamp connect status --stats type=bool
FLAG basecamp connect status --styled type=bool
FLAG basecamp connect status --todolist type=string
FLAG basecamp connect status --verbose type=count
FLAG basecamp docs --account type=string
FLAG basecamp docs --agent type=bool
FLAG basecamp docs --cache-dir type=string
Expand Down Expand Up @@ -18604,8 +18785,16 @@ SUB basecamp config trust
SUB basecamp config unset
SUB basecamp config untrust
SUB basecamp connect
SUB basecamp connect discard
SUB basecamp connect doctor
SUB basecamp connect import
SUB basecamp connect redispatch
SUB basecamp connect release
SUB basecamp connect setup
SUB basecamp connect shadow
SUB basecamp connect shadow promote
SUB basecamp connect show
SUB basecamp connect status
SUB basecamp docs
SUB basecamp docs archive
SUB basecamp docs doc
Expand Down
28 changes: 28 additions & 0 deletions e2e/smoke/smoke_lifecycle.bats
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,34 @@ load smoke_helper
mark_out_of_scope "Reads the connector policy a connected profile's setup wrote — covered by Go tests in internal/commands"
}

@test "connect status is out of scope" {
mark_out_of_scope "Reads a local connector ledger the smoke account does not have — covered by Go tests in internal/commands and internal/connector"
}

@test "connect doctor is out of scope" {
mark_out_of_scope "Needs a set-up connector profile and starts its MCP server — covered by Go tests in internal/commands"
}

@test "connect redispatch is out of scope" {
mark_out_of_scope "Decides a record in a local connector ledger — covered by Go tests in internal/commands and internal/connector"
}

@test "connect discard is out of scope" {
mark_out_of_scope "Decides a record in a local connector ledger — covered by Go tests in internal/commands and internal/connector"
}

@test "connect release is out of scope" {
mark_out_of_scope "Clears the hold in a local connector ledger — covered by Go tests in internal/commands and internal/connector"
}

@test "connect shadow promote is out of scope" {
mark_out_of_scope "Moves a local shadow ledger — covered by Go tests, including a process killed at every step, in internal/connector"
}

@test "connect import is out of scope" {
mark_out_of_scope "Applies a reconciliation file to a local connector ledger — covered by Go tests in internal/commands and internal/connector"
}

@test "auth refresh is out of scope" {
mark_out_of_scope "Requires OAuth credentials"
}
Expand Down
2 changes: 1 addition & 1 deletion internal/commands/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ func CommandCategories() []CommandCategory {
{Name: "bonfire", Category: "additional", Description: "Multi-chat orchestration", Actions: []string{"split", "layout"}, Experimental: true, DevOnly: true},
{Name: "api", Category: "additional", Description: "Raw API access"},
{Name: "mcp", Category: "additional", Description: "Serve Basecamp to MCP clients over stdio"},
{Name: "connect", Category: "additional", Description: "Set up a local agent connector for a Basecamp agent", Actions: []string{"setup", "show"}},
{Name: "connect", Category: "additional", Description: "Run a local agent connector for a Basecamp agent, and see and decide what it runs", Actions: []string{"setup", "show", "status", "doctor", "redispatch", "discard", "release", "shadow", "import"}},
{Name: "help", Category: "additional", Description: "Show help"},
{Name: "version", Category: "additional", Description: "Show version"},
},
Expand Down
17 changes: 13 additions & 4 deletions internal/commands/connect.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,17 @@ object per line (events seen, verdicts, dispatches, lifecycle messages;
never content), and logs
go to stderr. SIGINT and SIGTERM cancel live workers with stop reason
shutdown, settle them, and exit 130 and 143. --shadow admits and logs in an
isolated state directory and dispatches nothing. macOS and Linux only.`,
isolated state directory and dispatches nothing. --hold sets a durable hold:
intake and admission run, nothing dispatches or posts, and earlier records
wait for review, until basecamp connect release. macOS and Linux only.

basecamp connect status what it heard, holds and ran
basecamp connect doctor what it needs to run
basecamp connect redispatch <id> authorize a record to run
basecamp connect discard <id> close a record without running it
basecamp connect release clear the hold
basecamp connect shadow promote make the shadow ledger the connector's, held
basecamp connect import <file> apply a cutover reconciliation file`,
Example: ` basecamp connect setup -P agent --operator-profile me --route 12345=/src/app
basecamp connect -P agent
basecamp connect -P agent --project 12345 --shadow`,
Expand All @@ -64,9 +74,8 @@ isolated state directory and dispatches nothing. macOS and Linux only.`,
},
}
addConnectRunFlags(cmd, &run)
cmd.AddCommand(newConnectSetupCmd())
cmd.AddCommand(newConnectWorkerMCPCmd())
cmd.AddCommand(newConnectShowCmd())
cmd.AddCommand(newConnectSetupCmd(), newConnectWorkerMCPCmd(), newConnectShowCmd(), newConnectStatusCmd(), newConnectDoctorCmd(),
newConnectRedispatchCmd(), newConnectDiscardCmd(), newConnectReleaseCmd(), newConnectShadowCmd(), newConnectImportCmd())
return cmd
}

Expand Down
Loading
Loading