Skip to content

feat(agent): agent self-registration first slice (DEV-1, API contract rev 1) - #143

Merged
xergioalex merged 13 commits into
mainfrom
feature/agent-registration-first-slice
Oct 30, 2026
Merged

xergioalex merged 13 commits into
mainfrom
feature/agent-registration-first-slice

Conversation

@xergioalex

Copy link
Copy Markdown
Member

Summary

The CLI half of the agent self-registration first slice (DEV-1, Dailybot V3 → Product board), built against
API contract rev 1 (additive only; API side: PLAN_003_agent_registration_first_slice in the API repo).

Merge order

Merge only after the API PR for DEV-1 is deployed. That PR changes what the API returns: error codes,
claim_expires_at, and the self-registered key scope. This CLI falls back to detail against an older API,
but the docs and messages describe the rev-1 behaviour.

Change Log

  • User-Agent dailybot-cli/<ver> (python/<x.y>; <os>; <install_method>) on every request, including the
    presign upload and the storage download. Those two still send no Dailybot credential.
  • Registration challenge solved as code × len(instruction.split()). 52 is kept only as a sanity fallback.
    An unreadable instruction gives a clear error and a dailybot upgrade hint.
  • Retries: one retry on code: challenge_expired (legacy detail match when no code). A
    429 registration_rate_limited shows the Retry-After wait. The challenge GET uses the shared Retry-After helper.
  • Register output: the claim expiry comes from claim_expires_at (no hardcoded "30 days"), followed by a
    "Send this to your human" block. The API key is never printed.
  • Error codes: messages for every rev-1 registration/claim code. Agent commands dispatch on code and fall
    back to detail. plan_upgrade_required explains the registered-key scope and appends upgrade_url;
    invalid_credentials mentions a deactivated agent. agent configure accepts a key refused only for scope.
  • CLI-8: credentials/config/agents and the org/plan caches are created 0o600 from the first byte (os.open).
    The config dir is created 0o700.
  • Docs: README "Standalone registration" and docs/API_REFERENCE.md now match the contract: claim-token is a
    GET that returns the existing link, the claim needs a web login, and the key scope. The stale 401/403 wording
    is fixed in API_REFERENCE and SECURITY. Self-registration policy wording is unchanged.

Not in this PR (no backend in rev 1): --owner-email, CLI-6/7/9, the auth_required/claim_required/credential_* codes.

Validation

  • pytest -q → 3856 passed. tests/tui_app_flows_test.py and one textual-launch test are excluded locally
    only because textual is not installed in the dev container; CI installs it.
  • ruff check dailybot_cli tests → clean
  • mypy dailybot_cli → clean

Risks

  • Error messages change only for responses that carry a code; older servers keep showing detail.
  • No stored-file schema change; only file and directory creation modes.

🤖 Generated with Claude Code

xergioalex and others added 9 commits October 26, 2026 14:58
## Summary
Every request now carries `dailybot-cli/<ver> (python/<x.y>; <os>; <install_method>)`
so the backend can measure which CLI versions are in use before it changes the
registration challenge (DEV-1, API contract rev 1, item CLI-1).

## Change Log
- `user_agent()` (cached) and `_base_headers()` in api_client.py
- Anonymous, user-scoped, agent-scoped, alt-credential retry and streamed paths
  carry it; the credential-less storage hops get it too, still with no
  Authorization or X-API-KEY (a presign's own headers win)
- Agent-stamp tests now look for the agent-name header, not any "agent" substring

## Risks
- None for compatibility: an additional request header only

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

## Summary
Registration follows API contract rev 1 (DEV-1 items CLI-2 and CLI-3): the
challenge answer is the session code times the instruction's word count instead
of a hardcoded 52, so the server can vary the wording without breaking new CLIs.

## Change Log
- `_solve_challenge` counts words; 52 (`_CHALLENGE_LEGACY_WORD_COUNT`) is only a
  fallback for an implausibly short instruction; an unreadable one stops with a
  `dailybot upgrade` hint
- Retry once on code `challenge_expired` (legacy "expired" detail only when the
  server sends no code), always with a fresh challenge
- A registration 429 shows the Retry-After wait; the challenge GET waits out a
  short 429 (up to 10s) and never sleeps through a long one; the POST is never
  auto-retried because every attempt consumes its challenge
- docs/SECURITY.md describes the challenge as a speed bump and the key's scope

## Risks
- Registration against today's server is unchanged (52-word wording gives the
  same answer)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…o your human" block

## Summary
`dailybot agent register` now renders `claim_expires_at` (API contract rev 1)
instead of a hardcoded "30 days", and tells the agent exactly what to hand to
the human owner (DEV-1 item CLI-4, partial: `--owner-email` waits for server support).

## Change Log
- `format_claim_expiry` renders ISO 8601 as `YYYY-MM-DD HH:MM UTC`; without the
  field the CLI says "See the claim page for when it expires."
- The handoff text says the claim needs a Dailybot web sign-in and warns that
  the link works like a password
- Server-supplied names are escaped before Rich renders them; the API key is
  saved but never printed

## Risks
- Output wording change only

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…contract rev 1

## Summary
Agent commands and `agent register` now dispatch on the server's `code`
and fall back to `detail` for unknown or absent codes.

## Change Log
- ERROR_CODE_MESSAGES gains the rev-1 codes (challenge_*, invalid_answer,
  answer_incorrect, missing_fields, reason_*, registration_rate_limited,
  claim_token_unavailable)
- New agent_error_message(): agent-key copy for plan_upgrade_required (scope
  + upgrade_url) and invalid_credentials (deactivated agent), 429 wait hint
- `agent configure` treats a 403 plan_upgrade_required as a valid key
- Fixed the stale 401/403 wording in docs/API_REFERENCE.md and docs/SECURITY.md

## Risks
- Messages change only for responses that carry a code; old servers keep detail

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ir 0o700

## Summary
credentials.json, config.json, agents.json and the org/plan caches were
written with write_text then chmod, leaving a umask-permission window
while the file already held a token or key.

## Change Log
- New _write_secret_file(): os.open(..., 0o600), then chmod to tighten a
  pre-existing loose file
- get_config_dir() creates the directory 0o700 (an existing one is untouched)
- Six tests with chmod disabled under umask 0

## Risks
- None for stored-file schemas: content and names are unchanged

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
## Summary
README "Standalone registration" and the API reference now match the
contract: the server-reported claim expiry, the claim needing a web
sign-in, the least-privilege registered-key scope, the new response
fields and the rev-1 error codes. Policy wording is unchanged.

## Change Log
- README: no hardcoded "30 days"; claim needs a web login; key scope
  (agent email/webhook refused) and the free-plan daily cap
- API_REFERENCE: word-count challenge, expiry retry, rate limits, register
  response fields and 400/429 codes, claim preview/claim endpoints (web
  only), GET /v1/agent/claim-token/ (returns the existing link, no mint)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…a wait hint

The API throttle can omit Retry-After when it cannot compute a wait;
lock in the generic fallback.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…1 wire shapes

Copies the API's challenge wording, register 201 body (isoformat
claim_expires_at), 400/429 envelopes with Retry-After, and the
registered-key 403/429 bodies, and runs them through the real
DailyBotClient with only httpx mocked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@xergioalex xergioalex added the Ready Trigger AI code review label Oct 27, 2026
@github-actions

This comment has been minimized.

github-actions[bot]

This comment was marked as outdated.

@github-actions github-actions Bot added the pr-reviewed Passed AI code review label Oct 27, 2026
xergioalex and others added 3 commits October 27, 2026 19:34
…cret

os.open keeps an existing file's mode, so fchmod the descriptor before
the first byte (POSIX; Windows falls back to chmod after the write).
Applied to _write_secret_file and save_repo_env. AI review round 1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ricter expiry match

- Registration codes move to REGISTRATION_CODE_MESSAGES, read only by
  agent commands, so generic names never leak registration copy
- APIError carries the credential kind; the deactivated-agent-key copy
  is shown only when the request sent X-API-KEY
- Legacy (no code) challenge retry needs both 'challenge' and 'expired'
- A claim expiry without an offset is read as UTC
AI review round 1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AGENTS.md rule 11, SECURITY.md and STANDARDS.md still taught
write_text + chmod. AI review round 1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@xergioalex xergioalex added Ready Trigger AI code review and removed Ready Trigger AI code review labels Oct 27, 2026
@github-actions

This comment has been minimized.

github-actions[bot]

This comment was marked as outdated.

@xergioalex xergioalex added Ready Trigger AI code review and removed Ready Trigger AI code review labels Oct 27, 2026
@github-actions

This comment has been minimized.

github-actions[bot]

This comment was marked as outdated.

…d is PATCH

API #8241 now revokes a self-registered key when an org admin deletes the agent
from the dashboard, so the invalid_credentials copy and the API reference say
deleted, not deactivated. The registered-key allowlist lists PATCH for
agent-messages/read, which is what the client sends.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@xergioalex xergioalex added Ready Trigger AI code review and removed Ready Trigger AI code review labels Oct 27, 2026
@github-actions

github-actions Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

AI review for 3b4546b — ✅ done

View review →

Highest severity: info

Verifier: 0 checked · 0 verified · 0 downgraded · 0 refuted · 0 unverified · 0 skipped — grok-4.5 (economy), 0s

Strictness gate: ✅ highest severity info ≤ critical threshold

0 inline comment(s) attached.

Usage: 240.7k in (62% cached) · 2.7k out · est. $0.25 · 5 turns · 54s

Iteration-Aware Review: gen 3, round 1, policy=first-pass-exhaustive (new_commits, mode=incremental) — 0 surfaced.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code review — 0 finding(s): 0 critical · 0 warning · 0 info

Check: ✅ passing — strictness block-on-critical: highest severity info ≤ critical threshold

No findings posted inline.

Summary

Verdict

Looks good — this follow-up is a clean contract wording pass; nothing blocking.

What changed since last review

The delta (d9da1b8 → 3b4546b) only aligns copy and docs with API contract rev 1:

  • Agent invalid_credentials copy and tests now say an org admin may have deleted the agent (was “deactivated”).
  • Registered-key scope docs list PATCH /v1/agent-messages/read/ (the client already issues PATCH; this was a docs/client mismatch fix).
  • Error-table wording for the same deleted-agent case.

No auth-order, secret-file mode, challenge, or User-Agent behavior changed in this iteration.

Prior finding

The open info on user_agent()’s bare except Exception around detect_install_method() is still open: dailybot_cli/api_client.py is untouched in this delta, and detect_install_method() still only does offline path inspection with an internal "pip" fallback (it does not raise in normal failure modes). Harmless dead catch; not merge-blocking.

Cross-checks

  • Wire client already documents/uses PATCH /v1/agent-messages/read/ — docs now match.
  • Credential-aware invalid_credentials messaging (api_key only) was already in place; tests still cover the login-session non-blame path.
  • Secret-file 0o600 / config-dir 0o700 work from earlier commits is unchanged here.

Recommendation: approve


Since last review (d9da1b8 → 3b4546b): resolved 0 · still open 1 · regressed 0 · new 0.

Prior findings

  • still open dailybot_cli/api_client.py:51

Check status: ✅ passing — strictness block-on-critical, highest severity in effect info: highest severity info ≤ critical threshold.

This line is written by the reviewer runtime after the gate ran and matches the check conclusion and the tracking comment. Any recommendation above is the model's advisory opinion, not the gate.

@xergioalex
xergioalex merged commit cc72b63 into main Oct 30, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-reviewed Passed AI code review Ready Trigger AI code review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants