Add `hf knowledge-base` group: list/get/tree/topics, create/update/delete,
link/unlink to projects, and add/update/delete for topics, categories and
facts. Mirrors the project command style (flag parsing, JSON/table output,
token resolution). Registered in the dispatcher and the help surface, gated
on the knowledge-base.* permissions.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`assign-schedule-type` is registered in CommandSurface() as a Group, so
the default branch of main()'s switch picks it up via findGroup() and
hands it to handleGroup. handleGroup then treats args[0] (the agent-id)
as a subcommand name, fails findSubCommand, and errors:
unknown assign-schedule-type subcommand: <agent-id>
The group has no subcommands — it's a leaf — so the call never reaches
handleAssignScheduleType. Add an explicit top-level case before the
default branch so the leaf bypasses the group dispatcher.
Pre-fix repro:
$ AGENT_ID=ard hf assign-schedule-type analyst1 standard
unknown assign-schedule-type subcommand: analyst1
Post-fix:
$ AGENT_ID=ard CLAW_IDENTIFIER=server-t2 hf assign-schedule-type analyst1 standard
Assigned schedule type 'standard' to agent 'analyst1'
Surfaced during recruitment workflow Step 5 on prod (sherlock/agent-resource-director).
passmgr.GetToken returns an api-key in padded-cell mode (provisioned by
scripts/provision-hf-accounts.sh via 'hf user reset-apikey'), but every
call site funneled that through client.New which sent it as a
'Authorization: Bearer <hex>'. The HF backend's HTTPBearer middleware
expects JWT shape there and rejects hex strings as 'Could not validate
credentials'. The d2b83ad backend fix added a Bearer-fallback that tries
the value as an api-key, which masked the issue against current prod;
older backends or any future change in that fallback still 401.
Two changes:
- client.New auto-detects shape: 'eyJ'-prefix + two dots == JWT (Bearer),
anything else == api-key (X-API-Key). Empty token sets neither header.
- internal/help/surface.go's loadPermissionState (called by hf --help
introspection) switches to client.NewWithAPIKey explicitly so the
command-discovery path doesn't depend on the heuristic at all. When
that path failed silently (Known:false), agents would see only the
always-permitted commands ('user.*', 'agent.status', 'config',
'health', 'version') and conclude they had no project permission.
Adds internal/client/client_test.go covering both header paths plus
empty-token, isLikelyJWT cases, and NewWithAPIKey precedence.
Verified end-to-end in sim against a rebuilt hf-backend matching prod
(commit d2b83ad): cli with --token <api-key> sends X-Api-Key header,
backend returns 200 on /projects + /auth/me/permissions.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
surface.go declared project/create as Permitted: has(perms, "project.write"),
but the backend now (and the user-facing role editor's intent) uses
`project.create` as the dedicated create gate. Switching CLI and backend
to agree on the same perm so a role granted just `project.create` (e.g.
mgr in the new seed) can run `hf project create` without needing the
broader project.write.
Companion change to HarborForge.Backend@HEAD which adds project.create to
DEFAULT_PERMISSIONS, gives it to mgr by default, and rewrites the
POST /projects gate to consult it.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Implements NEXT_WAVE_DEV_DIRECTION.md §7.3 (was 4 lines of spec, never
shipped). Backend's POST /users has accepted agent_id+claw_identifier
since BE-CAL-003 but the cli never sent them, so historically every
agent user (zhi/lyn/mirror/sherlock/orion/nav on prod today) was
created with only the user row — agents table left empty, and all
downstream calendar/heartbeat/schedule-type flows that go through
_require_agent() returned 404.
## hf user create — new flags
--agent-id <id>
--claw-identifier <id>
Both required together (matches backend invariant). Either can come
from pcexec env: AGENT_ID env for agent-id, `openclaw config get
plugins.harbor-forge.identifier` for claw-identifier. Partial pair is
treated as "neither" so plain user creation (no binding intended) still
works without a 400.
## hf user bind-agent <username> — NEW subcommand
Backfills agents row for an existing user. PATCH
/users/{username}/bind-agent. Same accept --agent-id/--claw-identifier
flags + pcexec env fallback. requireBoth=true here — fail loudly if
the pair can't be resolved since the whole command is the binding.
## Wiring
- userCreatePayload gains AgentID + ClawIdentifier omitempty fields
- new userBindAgentPayload struct (both required)
- resolveAgentBinding helper shared by both commands
- main.go user create case parses --agent-id/--claw-identifier;
new user bind-agent case parses positional username + the same flags
- surface.go lists bind-agent so `hf user` and `hf --help` show it
Build: clean. Smoke-tested both subcommand usage strings.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The plan-schedule workflow needs to report agent runtime status
(idle/busy/on_call/exhausted/offline) at the end of planning, but the
cli had no wrapper for this — workflows were dropping inline curl in
the middle of their procedure to hit the backend.
This adds 'hf agent status --set <status> [--reason ...] [--recovery-at ...]'.
The endpoint identifies the agent purely from X-Agent-ID + X-Claw-Identifier
headers (no token), so the cli reads AGENT_ID from env and falls back
to hostname() for CLAW_IDENTIFIER if it isn't set — same convention
the openclaw plugin uses. Refuses to send if AGENT_ID env is missing,
since this only makes sense from a pcexec/agent runtime context.
Surface entry added so 'hf --help' lists it.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Verified against current code; fixed stale/inaccurate sections and
documented previously-undocumented features/flags/endpoints. Added a
"Part of the HarborForge platform" reference and role/port.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The reset-apikey command has its own auth mechanism via --acc-mgr-token,
so it should not be gated by permission introspection. This matches the
behavior of "user create" which is also Permitted: true.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The secret manager binary was renamed from pass_mgr to secret-mgr.
Update all references in CLI code, mode detection, and help text.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Allows reset-apikey to use --acc-mgr-token or auto-resolve from
secret-mgr in padded-cell mode, enabling API key provisioning
without an existing user Bearer token.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds `hf user reset-apikey <username>` to regenerate a user API key.
Requires user.manage permission. Returns the new key (shown once only).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add hf calendar command group to command surface and router
- Implement schedule/show/edit/cancel/date-list commands
- Implement plan-schedule/plan-list/plan-edit/plan-cancel commands
- Add leaf help for all calendar commands
- Align CLI with backend calendar routes and response envelopes
- Support virtual slot ids for edit/cancel
- Validate with go build and go test ./...
- Rename 'propose' group to 'proposal' in surface, leaf help, and routing
- Keep 'hf propose' as backward-compatible alias via groupAliases
- Add essential subcommand group: list, create, update, delete
- Accept command now shows generated story tasks in output
- Accept command supports --json output
- Task create blocks story/* types with helpful error message
- All help text updated to use 'proposal' terminology
- Add internal/commands/user.go with full user CRUD implementation
- Wire user subcommands in main.go dispatch
- Mark user subcommands as Permitted: true
- Support both padded-cell and manual mode for all user commands
- user create uses account-manager token flow per plan
- config: resolve binary dir, load/save .hf-config.json
- mode: detect padded-cell vs manual mode via pass_mgr
- client: HTTP client wrapper with auth header support
- passmgr: pass_mgr integration (get-secret, set, generate)
- output: human-readable + JSON output formatting with tables
- help: help and help-brief renderer for groups/commands
- commands: version, health, config (--url, --acc-mgr-token, show)
- auth: token resolution helper (padded-cell auto / manual explicit)
- main: command dispatcher with --json global flag support
- README: updated with current package layout and status