Skip to content

feat(run,automations): --context and checkout none (agent contexts C2) - #63

Merged
sre-helmcode merged 5 commits into
feat/ephemeral-e2-clifrom
feat/contexts-c2
Oct 27, 2026
Merged

sre-helmcode merged 5 commits into
feat/ephemeral-e2-clifrom
feat/contexts-c2

Conversation

@sre-helmcode

Copy link
Copy Markdown
Contributor

What

Agent contexts C2 (devops AGENT-CONTEXT.md §6 and §8 row C2), against the cloud-api B4 API (#406 runs, #407 automations).

  • nan run --context NAME: repeatable, at most 5, order kept, sent as contexts on POST /v1/runs. Works for workspace and ephemeral runs.
  • nan run --ephemeral without --repo is allowed only with --context: no github_repo is sent, and the agent works in an empty folder. --github-token-secret without --repo is refused.
  • nan automations create|edit --context NAME (repeatable, at most 5) and --checkout none (an ephemeral automation without a repository, which needs at least one context). edit takes the flags without -f. On edit, --checkout none also sends github_repo: null unless the file sets it. A field given both in the file and as a flag is refused.
  • Local checks, all exit 64 before any request: a sixth context, the same context twice (ids compared case-insensitively), a value that is neither a context name nor an id, an empty value, a file contexts: that is not a list, checkout: none with a repository, on a workspace automation, or with no context.
  • Server refusals with clear messages (exit 64): 404 context_not_found names the context from contexts[i], 422 context_skill_conflict, 413 context_too_large, and 400 on contexts[...]. On automations edit, a 404 context_not_found no longer reads as "automation not found".
  • api.Run now carries the pinned contexts (omitempty), so nan run --json shows them. The run announcement lists the contexts.
  • Help for nan run, nan automations create and edit, the README (flags table, ephemeral runs, the agent contexts section, exit codes).

Base and deviations

Tests (spec first)

  • cmd/run_contexts_test.go: order and body, no contexts without the flag, request goldens (cmd/testdata/contexts/run_request_*.json), a repo-less ephemeral run, a table of usage errors with no request sent, ids in any case, the flag run through cobra (repeat, a sixth one, a comma is not a separator), refusal mapping, Run.Contexts decoding, help.
  • cmd/automations_contexts_test.go: create/edit body goldens (automation_*.json), the file as written when no flags are given, edit without -f, a table of usage errors with zero requests, refusal mapping on create, on edit and from a file's contexts, help.
  • TestCheckAutomationExecutor: 13 new rows for checkout: none and contexts.
go build ./... && go vet ./... && go test ./...        ok
go test -race -shuffle=on ./...                         ok (cmd run 3 times with shuffle)
gofmt -l .                                              clean
GOOS=windows go build .                                 ok

🤖 Generated with Claude Code

sre-helmcode and others added 5 commits October 23, 2026 19:29
govulncheck, which CI runs as a failing check, reports GO-2026-6809
(crypto/x509 trusting compromised intermediates) on go1.26.9, reached
through every HTTPS call this CLI makes. It is fixed in go1.26.10. The
same finding is on main today, so without this the vulnerability job
fails here and on the next push to main, and tag.yml publishes nothing
from a commit whose CI did not pass.

Only the go directive moves; no dependency changes.

Co-authored-by: Pau Morillas <pmorillas@helmcode.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…ctor, 0.1.35 (#60)

nan auth login asks for the authenticator code (or a recovery code) after
the emailed link when the account has two-factor on, without echo, again
after a wrong one; --totp - reads it from stdin for scripts. The panel's
sign-in does the same. The verify call now sends mfa=1 so the platform can
answer with a challenge; with two-factor off the sign-in is unchanged.

Bumps internal/tui.Version to 0.1.35, which publishes the release.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ntexts C1) (#62)

* feat(context): nan context ls|show|create|push|pull|edit|rm (agent contexts C1)

The CLI side of agent contexts (helmcode/nan-devops AGENT-CONTEXT.md §6, C1),
against the /v1/contexts API merged in cloud-api (#391, #395).

- internal/contexts/path.go is a verbatim copy of cloud-api's validator, with
  its parity table (path_test.go) and a test of the shared pins.
- push: walks DIR, NFC-normalises names (macOS gives NFD), skips dotfiles
  with a notice, prints every refused file with its reason and exits 65
  before uploading unless --skip-invalid (CLAUDE.md gets a rename hint),
  checks the version limits, hashes, asks blobs/check, uploads only missing
  blobs (4 at a time; single PUT up to 16 MiB, multipart above, resumed
  within a push via the upload status and across pushes via a remembered
  upload id), publishes with base_version and an Idempotency-Key. Handles
  blob_missing (re-check, re-upload), version_conflict (exit 1, or --force
  shows the diff and rebases), context_secret_detected (--allow-secrets),
  per-file refusals and Retry-After (up to 2 minutes). --dry-run prints the
  add/change/remove list and the bytes to upload.
- pull: refuses a non-empty DIR (--force overrides), validates every server
  path with the shared validator before writing anything, writes through
  os.OpenRoot, pins downloads to the version read and verifies sha256/size.
- golang.org/x/text becomes a direct dependency at v0.39.0. CI gains a job
  (scripts/check-cloud-api-pins.sh, secret CLOUD_API_READ_TOKEN) comparing
  x/text, the Go toolchain's Unicode tables and path.go with cloud-api.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* ci: move the cloud-api parity check to cloud-api's CI

nan-cli is public and cloud-api private: cloud-api's CI reads this
repository's go.mod and path.go without a token, so the check lives there
and no secret is added here. The unit test keeps pinning golang.org/x/text
v0.39.0 and the Unicode tables (15.0.0).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(contexts): point the pins test at cloud-api's parity check

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(context): address the QA and Security review of #62

Security:
- A DIR that is a symlink is resolved once and its target walked; WalkDir
  alone saw one non-directory and push published an empty tree.
- push refuses to publish no files over a version that has some unless
  --allow-empty (also after a --force rebase).
- Files are hashed and uploaded through os.OpenRoot on DIR and refused if
  they stopped being regular files.
- pull downloads into a temporary name, verifies, sets the mode both ways
  and renames into place: a failed download never deletes a member's file,
  and a link or folder at a file's path is never replaced. The total of a
  version is capped at 250 MiB; a partial pull says how many files were
  written and points at --force.
- NAME|id is checked locally (context name or id) before any request.
- Remembered multipart uploads are keyed by API host and credential hash.

QA:
- Tests for a symlinked folder inside DIR and a symlinked file on pull,
  the blob_missing re-check body and single PUT, the version limits (31
  skills, 1001 files, 250 MiB, 100 MiB per file, SKILL.md 64 KiB), aborting
  an unusable remembered upload, forgetting an upload dropped mid-parts,
  exit mappings (entitlement_required and others), the inherited
  executable bit, pull --force modes, the total cap and local ref checks.
- Unchanged files keep the remote executable bit where the file system has
  none (Windows).
- Dead ContextVersions/ContextVersionInfo removed.
- The fake follows cloud-api's publish check order, decodes strictly and
  answers 411 without Content-Length.
- Help says API keys are not used here; pins comment wrapped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: barckcode <cristian@helmcode.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ne (agent contexts C2)

nan run --context NAME (repeatable, at most 5, order kept) sends
"contexts" on POST /v1/runs. An ephemeral run may leave out --repo only
with a context; --github-token-secret without --repo is refused.
nan automations create|edit take --context NAME and --checkout none
(an ephemeral automation without a repository, which needs a context);
edit accepts the flags without -f, and --checkout none on edit sets
github_repo to null unless the file says otherwise. A field given both
in the file and as a flag is refused.

Every mistake (a sixth context, a repeat, an invalid name, a contexts
field that is not a list) exits 64 before any request. The platform's
404 context_not_found (naming contexts[i]), 422 context_skill_conflict
and 413 context_too_large read as what to do, also on automation edit
where a 404 is no longer taken for a missing automation.

api.Run carries the pinned contexts so --json shows them. Request
goldens under cmd/testdata/contexts, help text and README.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sre-helmcode
sre-helmcode merged commit 0a1f967 into feat/ephemeral-e2-cli Oct 27, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants