hzhang 2176383729 fix(cli): send api-keys via X-API-Key in client.New + help surface
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>
2026-05-26 12:43:04 +01:00
2026-03-21 16:06:41 +00:00
2026-03-21 13:34:41 +00:00
2026-03-21 20:32:28 +00:00

HarborForge.Cli

HarborForge.Cli is the Go-based hf command-line client for HarborForge.

Part of the HarborForge platform. hf is a thin, scriptable client over the HarborForge.Backend REST API (default http://127.0.0.1:8000). It is permission-aware (command visibility derives from the caller's backend permissions) and supports both automatic secret resolution (padded-cell mode) and explicit --token auth (manual mode).

Build

go build -o ./bin/hf ./cmd/hf

Or use the bundled Makefile:

make build

To set the version at build time:

go build -ldflags "-X git.hangman-lab.top/zhi/HarborForge.Cli/internal/commands.Version=1.0.0" -o ./bin/hf ./cmd/hf

The Makefile versioned equivalent is:

make build VERSION=1.0.0

Run

# Show help
./bin/hf --help

# Show only permitted commands
./bin/hf --help-brief

# Show version
./bin/hf version

# Check API health
./bin/hf health

# Configure API URL
./bin/hf config --url http://your-harborforge:8000

# View current config
./bin/hf config

# JSON output
./bin/hf version --json

Install

Local install into a user bin directory

mkdir -p "$HOME/.local/bin"
go build -o "$HOME/.local/bin/hf" ./cmd/hf
chmod +x "$HOME/.local/bin/hf"

Make sure ~/.local/bin is on PATH before invoking hf directly.

OpenClaw profile install target

The OpenClaw plugin installer flow places the binary at:

~/.openclaw/bin/hf

If you want the equivalent manual install:

mkdir -p "$HOME/.openclaw/bin"
go build -o "$HOME/.openclaw/bin/hf" ./cmd/hf
chmod +x "$HOME/.openclaw/bin/hf"

Config location

hf resolves .hf-config.json relative to the binary directory, not the current working directory.

Examples:

  • if the binary is ~/.local/bin/hf, config lives at ~/.local/bin/.hf-config.json
  • if the binary is ~/.openclaw/bin/hf, config lives at ~/.openclaw/bin/.hf-config.json

This matters when testing multiple copies of the CLI side by side.

Quick start after install

hf config --url http://127.0.0.1:8000
hf --help-brief
hf health

Auth modes after install

  • Padded-cell mode (pass_mgr available): run commands directly and let hf resolve secrets automatically.
  • Manual mode (pass_mgr unavailable): pass --token to authenticated commands.

Examples:

# padded-cell mode
hf task list

# manual mode
hf task list --token "$HF_TOKEN"

Release Packaging

Cross-platform release builds are available through the Makefile:

make release VERSION=1.0.0

This produces versioned artifacts in dist/ using a stable naming pattern:

hf_<version>_<os>_<arch>
hf_<version>_<os>_<arch>.exe   # Windows

Current release targets:

  • linux/amd64
  • linux/arm64
  • darwin/amd64
  • darwin/arm64
  • windows/amd64

Examples:

  • dist/hf_1.0.0_linux_amd64
  • dist/hf_1.0.0_darwin_arm64
  • dist/hf_1.0.0_windows_amd64.exe

Package Layout

cmd/hf/          CLI entrypoint
internal/
  client/        HTTP client wrapper for HarborForge API
  commands/      Command implementations
  config/        Config file resolution and management (.hf-config.json)
  help/          Help and help-brief renderer with detailed leaf help
  mode/          Runtime mode detection (padded-cell vs manual)
  output/        Output formatting (human-readable, JSON, tables)
  passmgr/       pass_mgr integration for secret resolution

Runtime Modes

  • Padded-cell mode: When pass_mgr is available, auth tokens are resolved automatically. Manual --token flags are rejected.
  • Manual mode: When pass_mgr is not available, --token must be provided explicitly to authenticated commands.

Output / Error Contract

Human-readable mode

Default output is human-readable:

  • list commands render simple tables
  • get/detail commands render key-value output
  • empty lists render (no results)

JSON mode

--json can be supplied globally and produces structured JSON on stdout.

Current contract:

  • success payloads go to stdout as JSON
  • errors go to stderr as plain text
  • the CLI does not wrap successful payloads in a universal envelope yet
  • list/get payloads preserve canonical code-bearing fields whenever the backend already returns them

This is intentionally simple so agents can pipe hf ... --json into other tooling without first stripping banners or mixed text.

Exit / stderr conventions

Current CLI convention is:

  • exit 0 on success
  • exit 1 on command/validation/runtime errors
  • user-facing errors are written to stderr
  • success output is written to stdout

There is not yet a finer-grained exit-code taxonomy; callers should currently treat any non-zero exit as failure.

Current Status

Implemented

Foundation:

  • Go module and binary entrypoint
  • Config file resolution relative to binary directory
  • Runtime mode detection (pass_mgr present/absent)
  • HTTP client wrapper (GET/POST/PUT/PATCH/DELETE)
  • Output formatting (human-readable + --json)
  • Auth token resolution (padded-cell + manual)

Help system:

  • Top-level and group/leaf help rendering (--help / --help-brief)
  • Permission-aware command visibility via /auth/me/permissions
  • Detailed leaf help text for all commands, with padded-cell/manual auth flag differences
  • Nested help coverage for config, monitor server, monitor api-key, and proposal essential subtrees
  • (not permitted) rendering for unauthorized commands

Core commands:

  • hf version, hf health, hf config (show / --url / --acc-mgr-token)
  • hf update-discord-id <username> [discord-id] — top-level convenience command

Resource commands (all implemented with list/get/create/update/delete + special actions):

  • hf user — create, list, get, update, activate, deactivate, delete, reset-apikey
  • hf role — list, get, create, update, delete, set-permissions, add-permissions, remove-permissions
  • hf permission — list
  • hf project — list, get, create, update, delete, members, add-member, remove-member
  • hf milestone — list, get, create, update, delete, progress
  • hf task — list, get, create, update, transition, take, delete, search
  • hf meeting — list, get, create, update, attend, delete
  • hf support — list, get, create, update, take, transition, delete
  • hf proposal (alias: hf propose) — list, get, create, update, accept, reject, reopen
    • hf proposal essential — list, create, update, delete
  • hf calendar — schedule, show, edit, cancel, date-list, plan-schedule, plan-list, plan-edit, plan-cancel
  • hf comment — add, list
  • hf worklog — add, list
  • hf monitor — overview, server (list/get/create/delete), api-key (generate/revoke)

Pending

  • Backend code-based endpoint support (some commands still use id-based API routes)
  • Release automation beyond local make release packaging (checksums / archives / CI publishing)
  • Broader test coverage (unit tests exist for the calendar and proposal commands; end-to-end coverage is still partial)
Description
CLI tools for HarborForge
Readme 340 KiB
Languages
Go 99.7%
Makefile 0.3%