Skip to content

Let an agent connect an agent and manage connector setup: the basecamp-connect skill - #737

Merged
jorgemanrubia merged 12 commits into
mainfrom
connect-setup-skill
Sep 17, 2026
Merged

jorgemanrubia merged 12 commits into
mainfrom
connect-setup-skill

Conversation

@jorgemanrubia

@jorgemanrubia jorgemanrubia commented Sep 17, 2026 •

Copy link
Copy Markdown
Member

Connecting an agent and setting up the connector is two commands, basecamp auth agent connect and basecamp connect setup, with a dozen flags, a trust file and five exit codes. Today a person has to learn all of that and type it. It should be managed from an agent: the person says which projects and which directories, and the agent does the rest.

Tracked in 24 service install, the skill and the plugins. It follows Add basecamp connect setup: record trust, write connect.json, check readiness and Add the agent-connection handshake: basecamp auth agent connect.

Why

The setup half only needs those two commands, and both are merged, so it doesn't have to wait for the connector run. The skill is working knowledge an agent can manage from, with a guided first setup as one section of it.

What changes

  • A basecamp-connect skill in skills/, which ships where basecamp-doctor does. It covers:

    • the split between the two commands: which to run when, and in what order on a first setup; that setup never touches the credential; that changing the credential means running connect again.
    • where the credential, connect.json and the setup lock live, and what each connect.json field controls and which flag changes it. It also says never to hand-edit the file.
    • how to inspect the current setup without inventing a flag; setup has no dry run.
    • a guided first setup that picks projects by name, never by id, and prefers --operator-profile.
    • changing and removing routes and trust later, and the changes setup refuses on purpose.
    • every exit code and failed check in plain words. That includes Basecamp refusing project reads to an Agent identity (47 Admission's reads are refused under an Agent identity in bc3), which points to the bot-user profile.
    • rules that apply every time:
      • credentials stay out of the conversation, flags and files, and a hint to --with-token or --with-client-credentials is never followed.
      • the connection link and code are shown only locally.
      • basecamp me confirms the credential's identity before any setup.
      • numeric ids go into commands bare and every other value single-quoted, and project names reach a command only as numeric ids.
      • reconnecting, which rotates the agent's secret, needs the person's consent.
    • starting and supervising the connector, a service install subcommand, status/doctor/redispatch and the plugins, named as coming with card 24 behind step 21 so an agent does not look for them.
  • basecamp connect show -P <profile>, a read-only command that prints connect.json through setup's own loader, so a symlink, a file others could write, or another profile's policy is refused, not shown. It renders every setting for a person, not only as JSON. The skill inspects policy only through it, never with a raw file read.

  • Evals. Four cases, run against this skill's own SKILL.md (make -C skill-evals eval-connect, also part of make skill-eval):

    • a first-time setup;
    • a not_ready caused by the Agent-identity refusal;
    • routing a directory with a space and a $, for a project whose name contains $(...);
    • a credential whose identity is not the agent the person named.

    The runner can now grade the agent's final reply (accept_response / reject_response), since explaining a failure is the behavior under test.

  • Drift. make check-skill-drift covers the new skill, and the release manifest test expects it.

Verification

Neither this machine nor CI has an Anthropic API key, so CI's Skill Evals job skips. I ran the cases through the Claude Code CLI instead (Sonnet). A mock MCP server served the runner's basecamp tool and mocks, and the runner's own grade did the grading.

  • Against this skill: all four cases passed in 3 of 3 runs, on each head since they were added.

  • Against a deliberately wrong instruction, each case failed:

    Case Wrong instruction Failed
    first-time start the connector with a nonexistent basecamp connect run 2 of 2
    route quoting double-quote values 2 of 2
    identity skip basecamp me and go straight to setup 2 of 2
    not_ready call the Agent refusal a stale credential and reconnect 1 of 2

    In the passing not_ready run the model followed setup's own hint over the skill.

  • Mutations that proved nothing. Two earlier wrong instructions did not make their case fail, because the model refused or ignored them: pasting a token into auth login --with-token, and dropping quoting altogether. They are not counted as proof.

Every command and flag in the skill was also checked against the exact .surface command, not the parent-resolving drift check. A mutated flag or subcommand fails that check. bin/ci passed on the head that adds connect show. Its refusal tests go red against a raw read of the file and pass with the loader.

… setup

A reference an agent works from to connect a Basecamp agent and manage
basecamp connect setup for a person: which of auth agent connect and
connect setup to run when, what connect.json holds and how each part is
changed, how to inspect it, and how to explain every setup exit code and
failed check, including Basecamp refusing reads to an Agent identity.
Starting and supervising the connector is named as not built yet.

The skill gets its own eval cases, run against its own SKILL.md, and the
eval runner can now grade the agent's final reply as well as its commands.
Copilot AI balanced review requested due to automatic review settings September 17, 2026 05:50
@github-actions

Copy link
Copy Markdown

Sensitive Change Detection (shadow mode)

This PR modifies control-plane files:

  • .github/workflows/test.yml

Shadow mode — this check is informational only. When activated, changes to these paths will require approval from a maintainer.

@github-actions github-actions Bot added tests Tests (unit and e2e) ci CI/CD workflows skills Agent skills docs labels Sep 17, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The guided workflow can select an unverified Agent identity and emits commands without safely quoting dynamic values.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Adds the basecamp-connect skill and evaluation coverage for agent credential and connector setup workflows.

[!TIP]
If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or run gh pr ready --undo.
Click "Ready for review" or run gh pr ready to reengage.

Changes:

  • Documents guided connector setup, trust, routing, readiness, and recovery.
  • Adds response-aware skill evaluation and two connector scenarios.
  • Integrates the skill into CI, drift checks, release validation, and contributor guidance.
File summaries
File Description
skills/basecamp-connect/SKILL.md Adds the connector-management skill.
skill-evals/run Grades final agent responses.
skill-evals/Makefile Adds the connector eval target.
skill-evals/cases/basecamp-connect/not-ready-agent-reads.yml Tests Agent-read refusal handling.
skill-evals/cases/basecamp-connect/first-time-setup.yml Tests first-time setup behavior.
Makefile Adds drift and eval integration.
internal/release/manifests_test.go Validates the new skill path.
AGENTS.md Documents drift and eval coverage.
.github/workflows/test.yml Triggers evals for skill changes.
Review details

Suppressed comments (1)

skills/basecamp-connect/SKILL.md:217

  • The agent substitutes local profile names and directory paths into this shell command, but the example leaves those values unquoted. A route such as /home/me/Work/Redesign 2 is split into multiple arguments, and shell metacharacters can be interpreted. Require shell-quoting every substituted value, consistent with internal/commands/files.go:1903-1918 and internal/commands/templates.go:295-300.
basecamp connect setup -P <profile> --operator-profile <operator-profile> \
  --route <project-id>=<dir> --route <project-id>=<dir> --json
  • Files reviewed: 9/9 changed files
  • Comments generated: 3
  • Review effort level: Balanced (auto)

Note

Copilot is running an experiment and ran this review at Balanced.


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread skill-evals/cases/basecamp-connect/first-time-setup.yml
Comment thread skills/basecamp-connect/SKILL.md Outdated
Comment thread skills/basecamp-connect/SKILL.md Outdated
… found

The skill now confirms who a profile's credential is (basecamp me) before
setting it up, and stops when it is not the agent the person named. It
single-quotes every value it puts into a command and resolves project
names to ids before they reach one.

From review: the bot user signs in to a new profile with profile create;
the auth code is auth_required and an unknown profile is api_error (exit
7, shared with not_ready); interactive logins run without machine output
or BASECAMP_NONINTERACTIVE, in the background, and never follow a hint to
--with-token or --with-client-credentials; the link and code stay in the
local conversation; reconnecting rotates the agent's secret, so it needs
consent and is never used on a bot-user profile; auth status is read
precisely; moving XDG_CONFIG_HOME hides every profile; the last route
cannot be removed alone; lookups name their profile.

Evals: route-quoting and unconfirmed-identity cases, a realistic
auth agent connect mock with a --json rejection, and quote-tolerant
patterns.
Copilot AI review requested due to automatic review settings September 17, 2026 06:08

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Directly reading connect.json bypasses its security validation and could expose an arbitrary symlinked local file.

Get a fresh assessment by requesting another Copilot review.

Review details
  • Files reviewed: 11/11 changed files
  • Comments generated: 1
  • Review effort level: Balanced (auto)

Note

Copilot is running an experiment and ran this review at Balanced.

Comment thread skills/basecamp-connect/SKILL.md Outdated
The skill had an agent read connect.json with a plain file read, which
skips the no-follow, ownership and permission checks setup.Load applies:
a planted symlink could put any local file into the conversation.

basecamp connect show prints a profile's connect.json through
setup.Load, changing nothing and making no request; a symlink, a file
others could write, or one that does not parse is refused and nothing of
it is shown. The skill now inspects policy only through it and says never
to read the file directly. The eval cases mock it.
Copilot AI review requested due to automatic review settings September 17, 2026 06:23
@github-actions github-actions Bot added the commands CLI command implementations label Sep 17, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The default human output for connect show omits the nested agent, trust, and project policy fields.

Get a fresh assessment by requesting another Copilot review.

Review details
  • Files reviewed: 16/16 changed files
  • Comments generated: 1
  • Review effort level: Balanced (auto)

Note

Copilot is running an experiment and ran this review at Balanced.

Comment thread internal/commands/connect.go Outdated
The generic styled and Markdown renderers drop nested maps, which is
where the agent, the trust and the routes live, so show printed a
summary and the worker settings to anyone not using --json. Show now
renders those formats itself, one setting to a line with the routes in
project order. The not_found hint quotes its placeholders, and on
Windows the refusal says the trust file is unsupported there rather
than asking to fix a file.
Copilot AI review requested due to automatic review settings September 17, 2026 06:32

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Connector policy display misses profile-binding validation, and the skill’s examples contradict its required quoting rule.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

skills/basecamp-connect/SKILL.md:89

  • The stated invariant and PR scope require every substituted command value to be single-quoted, but later runnable templates leave <account-id>, <bot-identity-id>, <id>, and <person-id> bare (for example lines 234–236, 250, 279, 293–297, 356, and 370). This gives the agent conflicting instructions and the evals do not cover most of these paths. Quote those placeholders consistently, or narrow the rule and PR claim if only shell-sensitive values are intended.
  • Files reviewed: 16/16 changed files
  • Comments generated: 1
  • Review effort level: Balanced (auto)

Note

Copilot is running an experiment and ran this review at Balanced.

Comment thread internal/commands/connect.go
…ind of value

connect show accepted a valid policy copied from another profile's
directory and labelled it as this profile's; setup refuses that, and now
show does too. Its human output shows route paths exactly: quoted for a
terminal, a code span in Markdown.

The skill said to single-quote every value while its templates left ids
bare. It now has one rule for each kind of value: numeric ids bare and
checked to be digits, everything else single-quoted.
Copilot AI review requested due to automatic review settings September 17, 2026 06:47

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Markdown output can expose terminal controls, and response evals can incorrectly accept truncated model replies.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (3)

Previously missed (2) — in code that hasn't changed since the last review.

skill-evals/run:124

  • This treats any response without a tool call as the final reply, even when Anthropic reports stop_reason: "max_tokens". A truncated reply can therefore satisfy accept_response and pass the new final-response grading. Check stop_reason and fail the sample unless the terminal response completed normally.
    skills/basecamp-connect/SKILL.md:155
  • The documented class grammar omits that the first character must be a lowercase letter or digit (setup.ValidClass uses ^[a-z0-9][a-z0-9_-]{0,39}$). As written, the skill can recommend values such as _internal that setup rejects. Include the leading-character requirement.

This issue also appears on line 225 of the same file.

skills/basecamp-connect/SKILL.md:226

  • The documented profile grammar omits that the first character must be a letter or digit; isValidProfileName rejects leading - or _ (internal/commands/profile.go:625-629). State that constraint so the guided flow does not choose a profile name that all three commands reject.
**1. Profile and credential.** Agree on a profile name: letters, digits, `-`
and `_` only, for example the agent's name. Inspect it (steps 1 to 3 above).
  • Files reviewed: 16/16 changed files
  • Comments generated: 1
  • Review effort level: Balanced (auto)

Note

Copilot is running an experiment and ran this review at Balanced.

Comment thread internal/commands/connect.go Outdated
…; exact name grammars

connect show's Markdown output put a route path in a code span raw, and
a clean absolute path can hold ESC or C1 controls: they are now written
as escapes, as the styled output already quotes them.

The eval runner treated a reply cut off at max_tokens as final, so a
truncated reply could satisfy accept_response; it now fails the sample.

The skill states that profile names and class labels start with a letter
or digit, as the CLI requires, and quotes the profile placeholder in its
overview too.
Copilot AI review requested due to automatic review settings September 17, 2026 06:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Markdown output does not safely delimit the configurable policy file path.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

internal/commands/connect.go:137

  • In Markdown mode the config path is inserted as raw Markdown. XDG_CONFIG_HOME can contain brackets or backticks, so a valid path can render as a link or alter the document instead of being shown literally; route paths are already code-fenced for this reason. Render the file path as an escaped code span in Markdown mode as well.
  • Files reviewed: 16/16 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced (auto)

Note

Copilot is running an experiment and ran this review at Balanced.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The first-time eval does not reject every machine-output mode refused by the real interactive connection command.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

skill-evals/cases/basecamp-connect/first-time-setup.yml:41

  • The real interactive-login gate also rejects --ids-only, --count, and --jq (internal/commands/auth.go:1254-1276), but this broad success mock plus the current rejection allows an agent using any of those machine-output modes to pass the first-setup eval. Include all three so this case actually enforces its “interactive connection uses no machine output” behavior.
  • Files reviewed: 16/16 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced (auto)

Note

Copilot is running an experiment and ran this review at Balanced.

…connection

The login gate also refuses --ids-only, --count and --jq.
@jorgemanrubia

Copy link
Copy Markdown
Member Author

🤖 The last Copilot review noted, in a suppressed comment, that the first-time eval didn't reject every machine-output mode. Fixed in 0fe4428: the rejection now also covers --ids-only, --count and --jq on auth agent connect, matching the login gate.

Copilot AI review requested due to automatic review settings September 17, 2026 07:08

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The custom human renderer bypasses global styled-output and statistics behavior.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

internal/commands/connect.go:115

  • This direct write bypasses the output pipeline for both human formats. Consequently basecamp connect show --styled emits no ANSI despite --styled meaning “Force styled output (ANSI colors)” (internal/cli/root.go:249), and --stats is silently omitted even though App.OK adds it and both styled/Markdown renderers display it (internal/appctx/context.go:263-272, internal/output/render.go:143-159, internal/output/render.go:1259-1263). Please route the custom policy presentation through an output-rendering hook/type, or otherwise preserve these global format features instead of returning after fmt.Fprint.
  • Files reviewed: 16/16 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced (auto)

Note

Copilot is running an experiment and ran this review at Balanced.

Show wrote its styled and Markdown text straight to stdout, so --styled
emitted no ANSI and --stats was dropped. It now hands the renderer a flat
display view (one field per setting and per route, paths quoted or code
spanned) through WithDisplayData, and JSON keeps the file's own shape.
@jorgemanrubia

Copy link
Copy Markdown
Member Author

🤖 The last Copilot review noted, in a suppressed comment, that show's human output bypassed the output pipeline (no ANSI under --styled, no --stats). Fixed in a959517: show now passes a flat display view through app.OK with WithDisplayData, one field per setting and per route, with paths quoted, or code-spanned and escaped in Markdown. The styled and Markdown renderers, stats and summary all apply. JSON is unchanged. The every-setting test goes through the real writer and fails without the display view.

Copilot AI review requested due to automatic review settings September 17, 2026 07:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Two connector evals can pass while targeting the wrong profile.

Review details

Suppressed comments (2)

Previously missed (2) — in code that hasn't changed since the last review.

skill-evals/cases/basecamp-connect/not-ready-agent-reads.yml:20

  • The eval accepts a route update without asserting -P/--profile helper. Because the real CLI otherwise resolves an active/default profile, a response can pass this not-ready scenario after attempting the change against the wrong connector profile. Require the named profile in the accepted setup invocation.
    skill-evals/cases/basecamp-connect/route-quoting.yml:19
  • This assertion does not require the setup command to target the helper profile, so connect setup --route '222=…' can pass even though it may modify whichever profile is active instead of the agent named by the task. Add a separate acceptance pattern for -P/--profile helper, as the first-time case already does.
  • Files reviewed: 16/16 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced (auto)

Note

Copilot is running an experiment and ran this review at Balanced.

The styled renderer converts a value it takes for HTML, so a route path
holding <b> lost it. Paths now escape < as \x3c in both formats, and a
test pushes a path with HTML, a link and backticks through the real
renderers. The route count reads before the routes, and the two
connector evals require the setup run to name the profile.
@jorgemanrubia

Copy link
Copy Markdown
Member Author

🤖 The last Copilot review noted, in suppressed comments, that two connector evals accepted a setup run without asserting the profile. Fixed in faf9e7d: not-ready-agent-reads and route-quoting now both require -P helper on the setup call, as the first-time case does. The same head fixes a real find from the adversarial review: the styled renderer rewrites a value it takes for HTML, so a route path containing <b> lost it. Paths now escape < as \\x3c in both human formats, and a new test sends a path with HTML, a Markdown link and backticks through the real renderers.

Copilot AI review requested due to automatic review settings September 17, 2026 07:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The first-time flow can retain undisclosed existing policy, and the catalog advertises unavailable connector execution.

Review details

Suppressed comments (2)

Previously missed (2) — in code that hasn't changed since the last review.

internal/commands/commands.go:149

  • The catalog still tells users this command runs a connector, but this PR and the command itself explicitly state that starting/running is not implemented; only setup and show exist. Update the user-facing description so help does not advertise unavailable behavior.
    skills/basecamp-connect/SKILL.md:226
  • This first-time flow explicitly skips the policy inspection in step 4. If the named profile already has connect.json, setup preserves every route and setting not passed, so the flow can add the requested route while leaving undisclosed old trust/routes in place. Inspect the policy too and switch to the later-change flow when one exists.
  • Files reviewed: 16/16 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced (auto)

Note

Copilot is running an experiment and ran this review at Balanced.

The guided first setup skipped inspection, so adding a route to a
profile that already had one would keep trust and routes nobody had
mentioned. It now inspects first and hands over to the change flow when
a policy exists.

The command catalog said connect runs a local agent connector; it sets
one up. The eval mocks answer per profile, so a run that checks the
operator's profile gets the operator's answer.
@jorgemanrubia

Copy link
Copy Markdown
Member Author

🤖 The last Copilot review noted two suppressed comments, both fixed in 6a5b35b. The catalog description now says connect sets up a connector rather than runs one, matching the command's own help. And the guided first setup now inspects the profile fully first: if connect show prints a policy the profile is already set up, so the skill says what it holds and goes to the change flow, instead of adding a route while keeping trust and routes nobody mentioned.

Copilot AI review requested due to automatic review settings September 17, 2026 07:46

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

connect show -P cannot reach its intended not-found handling for unknown profiles because root profile resolution rejects them first.

Get a fresh assessment by requesting another Copilot review.

Review details
  • Files reviewed: 16/16 changed files
  • Comments generated: 1
  • Review effort level: Balanced (auto)

Note

Copilot is running an experiment and ran this review at Balanced.

Comment thread internal/commands/connect.go
An unknown -P is refused for every command before it runs, which is how a
typo is told from a profile that exists with no connector policy. Show's
help and the skill now say so, instead of implying not_found covers both.
Copilot AI review requested due to automatic review settings September 17, 2026 07:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approved

The implementation, security checks, documentation, and automated coverage are consistent and no unresolved defects were identified.

Review details
  • Files reviewed: 16/16 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced (auto)

Note

Copilot is running an experiment and ran this review at Balanced.

@jorgemanrubia
jorgemanrubia merged commit fec4989 into main Sep 17, 2026
26 checks passed
@jorgemanrubia
jorgemanrubia deleted the connect-setup-skill branch September 17, 2026 07:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci CI/CD workflows commands CLI command implementations docs skills Agent skills tests Tests (unit and e2e)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants