Skip to content

kickoff agent: macOS-Keychain auth gap + unsanctioned rewrite of --doc design file #580

@maxine-at-forecast

Description

@maxine-at-forecast

Two distinct kickoff bugs surfaced during a real-world --container docker run on macOS. They share a common entrypoint surface so I'm filing together; happy to split if preferred.

Bug 1 — macOS Keychain auth gap

What

The container entrypoint (`crosslink/resources/container/entrypoint.sh`) only handles auth via:

```bash
if [ -f /host-auth/.credentials.json ]; then
cp /host-auth/.credentials.json /home/agent/.claude/.credentials.json
```

On macOS, claude CLI stores its OAuth credentials in Keychain, not in `/.claude/.credentials.json`. Result: `/host-auth/` (which is `/.claude` bind-mounted) has no `.credentials.json`, the conditional skips, the agent boots without auth, and claude CLI prints:

```
Claude configuration file not found at: /home/agent/.claude/.claude.json
A backup file exists at: /home/agent/.claude/backups/.claude.json.backup.
[...]

Not logged in · Please run /login
```

The agent then either hangs forever or exits silently depending on flags.

Reproduction

  1. macOS host with claude CLI authenticated via OAuth (Keychain). `ls ~/.claude/` shows no `.credentials.json`.
  2. `crosslink kickoff run --container docker --skip-permissions `
  3. Container starts. `docker logs ` shows the "Claude configuration file not found" loop.

Suggested fix

Have the entrypoint additionally honor `CLAUDE_CODE_OAUTH_TOKEN` (and/or `ANTHROPIC_API_KEY`) as fallbacks, with a prioritized order:

  1. `/host-auth/.credentials.json` (Linux hosts with claude logged in via that file).
  2. `/host-auth/.kickoff.env` (or any `/host-auth/*.env`) sourced into the agent's environment, picking up `CLAUDE_CODE_OAUTH_TOKEN`.
  3. Pass-through environment variable from `crosslink kickoff run` itself (which currently has no `--env` flag — see #N for that piece).

Optionally: emit a clear error message if no auth path resolves, instead of falling through silently.

Workaround in use

A santana-local entrypoint wrapper at `forecast-bio/santana@feature/post-m0-bootstrap:scripts/santana-entrypoint.sh` sources `/host-auth/.kickoff.env` before delegating to the upstream entrypoint:

```bash
KICKOFF_ENV="/host-auth/.kickoff.env"
if [ -f "$KICKOFF_ENV" ]; then
set -a; source "$KICKOFF_ENV"; set +a
fi
exec /usr/local/bin/crosslink-entrypoint.sh "$@"
```

Plus a santana-local Dockerfile that installs the wrapper as ENTRYPOINT. Works but is redundant once this is fixed upstream.


Bug 2 — kickoff agent rewrote the design file passed via `--doc`

What

`crosslink kickoff run --doc <path/to/design.md>` is documented as supplying the canonical design doc as input to the agent. In a real run, the agent edited the design file itself during scaffolding work, dropping ~85 lines of content (including OPEN-question markers) and replacing the title heading.

Reproduction

  1. `crosslink kickoff run "M0: ..." --doc .design/.md ...`
  2. Agent runs to completion, commits include the design file as modified. PR is opened.
  3. Diff shows the agent re-templated the design doc (e.g. dropped a section, restructured headings). The post-merge state on `main` no longer matches the canonical version that was passed in.

Concrete instance

In the santana repo's M0 milestone, the agent rewrote `.design/santana-token-ar.md` from 402 lines to 317 lines, including dropping three `` blocks (Q1, Q2, Q3) that captured genuine open architectural questions. The file's recorded `doc_hash` in `.design/.pipeline.json` (the kickoff infra's own state file) still pointed to the canonical sha256, mismatching the new committed content.

The post-M0 fix-up PR is at forecast-bio/santana#2 — restoring the canonical version.

Suggested fix

Treat the `--doc ` input as read-only in the agent's allowed-tool surface. Concretely:

  1. Mount the design doc at a stable path in the container (e.g. `/workspaces/repo/.design/.md`) but read-only, OR
  2. After the agent run completes, validate that `sha256()` matches the `doc_hash` already recorded in `.kickoff-plan.json` / `.pipeline.json`. Fail the kickoff (or at minimum produce a clear warning surfaced to the agent's report) if the hashes diverge.
  3. Document explicitly in `KICKOFF.md` (the in-context prompt) that the design doc is canonical input, not a working file.

Option 2 is the lighter-weight fix and would have caught this M0 issue at the validation step before the PR went up.


Environment

Cross-refs

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions