hadron-cli

module
v0.8.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 23, 2026 License: MIT

README

hadron-cli

hadron is the command-line interface to the Hadron AI-memory platform, for humans working in a terminal and AI agents shelling out to it.

Status

Implemented v1 command surface: auth login|logout|whoami|status, memory ls|get|set|rm|clone|export, node ls|get|add|update|rm, spec ls|get|describe|register|find|new|edit|extract|link|lint|supersede|use, app ls|install|uninstall|use, config get|set|list, api (raw GraphQL escape hatch), replace, version, completion, agentic-usage. spec import spec-kit|code is reserved as a stable command stub but is not yet implemented.

Specs follow a legal-code citation scheme — flat (<module>:<feature>:<rule>) or product-rooted (<product>:<module>:<feature>:<rule>) for a multi-product corpus — with a general-provisions contract at every tier (feature :00, module :000, product :gen). See docs/how-to/maintain-product-specs.md.

Install

Homebrew (macOS)
brew tap hadron-memory/hadron-cli
brew install --cask hadron
Release archives (macOS, Linux, Windows)

Download the archive for your platform from the latest release, verify it, and put hadron on your PATH.

checksums.txt is signed with cosign keyless, so you can confirm it came from this repo's release pipeline before trusting the checksums in it. Download checksums.txt and checksums.txt.sigstore.json (the Sigstore bundle — cert + signature in one file) from the release, then:

# 1. Verify the checksum manifest was signed by this repo's release workflow.
cosign verify-blob \
  --bundle checksums.txt.sigstore.json \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-identity-regexp '^https://github.com/hadron-memory/hadron-cli/\.github/workflows/release\.yml@refs/tags/v' \
  checksums.txt

# 2. Only once that prints "Verified OK", check your archive against it.
shasum -a 256 -c checksums.txt --ignore-missing

The --certificate-identity-regexp pins the signer to the release workflow on a v* tag in this repo — without it, cosign would accept a signature from any GitHub identity. Verifying the signature first is what makes the checksum meaningful: the manifest is co-hosted with the archives, so checking an archive against an unsigned checksums.txt only proves they agree with each other.

On Windows, run the above from WSL or Git Bash, or use the native cosign.exe with PowerShell's Get-FileHash checksums.txt for the checksum step.

Go
go install github.com/hadron-memory/hadron-cli/cmd/hadron@latest

(go install builds without the version stamp — hadron version reports dev.)

From source
make build        # produces bin/hadron, version-stamped

Requires Go (see go.mod for the version).

Quick start

hadron auth login                         # browser OAuth via GitHub (default)
hadron auth login --provider google       # browser OAuth via Google
hadron auth whoami
hadron memory ls --json
hadron api 'query { me { id email } }'

For CI/scripting, mint a token with hadron auth token create, then set HADRON_TOKEN or pipe it to hadron auth login --with-token. None of the ways to authenticate require the web portal — a self-hosted hadron-server is enough; see Authentication.

For AI agents

Run hadron agentic-usage — it prints the full output contract, stable exit codes, and recipes in one document. Every command supports --json with stable field names.

Claude Code plugin

This repo is also a Claude Code plugin marketplace. In Claude Code:

/plugin marketplace add hadron-memory/hadron-cli
/plugin install hadron-cli@hadron-cli

The hadron-cli plugin ships a use-hadron-cli skill that teaches the agent the CLI contract (auth checks, --json, --yes on destructive commands, fully-qualified node URNs) and defers to hadron agentic-usage as the runtime source of truth.

Driving headless runs

hadron is the open-source counterpart to the closed-source portal: the spec-040 headless-run surface (cor:agt:010) is fully drivable from the CLI, so a self-hosted deployment needs no portal to schedule and operate agent runs. A run executes an entry (prompt) node under an App's identity, off any interactive session; run, schedule, and webhook are three triggers into the same kernel, and ticket is the action-budget ledger.

End to end — pick the model, name the work, schedule it, watch the runs:

# 1. AI config the runs will use (App→Agent→Org→Host walk; innermost wins).
printf '%s' "$ANTHROPIC_KEY" | hadron ai-config create --app acme.com:ops \
  --name default --provider anthropic --model claude-opus-4-8 --api-key -

# 2. The entry node — an ordinary prompt/task node in one of the App's memories.
hadron node add -m acme.com::ops --loc tasks:nightly-digest --type task \
  --name 'Nightly digest' --content 'Summarize today's incidents and email the team.'

# 3. Schedule it. --as-self runs on behalf of you, so it can reach your
#    personal memories (an App-key caller cannot use --as-self).
hadron schedule create --app acme.com:ops --name nightly-digest \
  --cron '0 6 * * *' --tz America/New_York \
  --entry acme.com::ops::tasks:nightly-digest --as-self

# 4. Mint the outbound-comms budget the runs consume (org ADMIN).
hadron ticket mint --org acme.com --action comm.outbound --count 100 \
  --note 'nightly digest sends'

# 5. Trigger one now to test, waiting for the terminal status; then audit.
hadron run trigger --app acme.com:ops \
  --entry acme.com::ops::tasks:nightly-digest --as-self --wait --json
hadron run ls --app acme.com:ops --status FAILED --json
hadron run get <run-id> --json          # budgets, policy, failure payload

Webhooks are the push variant: hadron webhook create --app <ref> --name <n> --entry <node-urn> prints a URL path and platform token once (POST to fire the run) — capture them then, as the secret is never queryable again. hadron webhook rotate <id> reissues it. Full flag reference: hadron agentic-usage.

CLI coverage and deliberate exclusions

Everything the platform can do is meant to be drivable from hadron. The headless-run surface above closes the spec-040 gap. Some server GraphQL operations have no dedicated command by design — they are reachable through the hadron api raw-GraphQL escape hatch when needed:

  • Interactive / portal-only flows — chat and session lifecycle (startChat, sendChatMessage, startSession, …), the system-memory editor lock and revision/version machinery, multipart asset upload, and invitation / onboarding / profile mutations. These are browser-interaction shaped, not batch-CLI shaped.
  • Git-sync internalsreplaceSubtree, mergeMemories/mergeNodes, pushMemoryToGit/syncMemory, setMemorySourceToken, encryptMemory. These are server↔git machinery; the CLI's memory export/node import cover the end-user round-trip.
  • Not-yet-built, tracked as follow-ups — the Agent surface (agent CRUD, AI config wiring, subscriptions, imports) has no command group yet; one-time schedules (schedule create --at <iso>), and the admin grants/policy/quota surface are blocked on server work (hadron-server#510, #501). See issue #134's comment thread for the running list.

Development

make build      # build with version stamp
make test       # go test ./...
make lint       # golangci-lint run
make generate      # regenerate genqlient code from schema/schema.graphql
make schema        # refresh schema snapshot from ../hadron-server, then generate
make schema-check  # fail if the committed snapshot is stale vs ../hadron-server

The GraphQL schema snapshot at schema/schema.graphql is exported from hadron-server (pnpm schema:export there) and committed here; typed operations live in internal/api/queries/*.graphql and are compiled by genqlient. CI fails if generated code drifts from the committed schema.

That per-PR check only compares the generated client against the committed snapshot, so it can't catch the snapshot itself lagging the server (e.g. a server-side appIdappRef rename). make schema-check closes that gap: it re-exports the SDL from ../hadron-server and fails if the generated client would change for an operation the CLI uses (server changes the CLI doesn't touch are ignored). The schema-drift workflow runs it nightly against the server's main; enable it by adding a HADRON_SERVER_RO_TOKEN repo secret (a token with read access to the private hadron-server repo). Without the secret the job no-ops.

Releasing

Build and test locally first, then cut the release by pushing a semver tag:

git checkout main && git pull        # release from a green main
make build && make test              # verify the build works
./bin/hadron --help                  # sanity check
git tag -a v0.3.0 -m "v0.3.0"        # bump per semver
git push origin v0.3.0

The tag triggers .github/workflows/release.yml, which runs goreleaser (.goreleaser.yaml) to:

  • cross-compile darwin/linux/windows (amd64/arm64) binaries — version-stamped from the tag — into archives + checksums.txt;
  • sign checksums.txt with cosign keyless (GitHub OIDC — no key material), emitting the checksums.txt.sigstore.json bundle (the job needs id-token: write; see the verification steps under Release archives);
  • codesign + notarize the macOS binaries — only when the signing secrets are configured (see macOS signing below); otherwise skipped and the release ships unsigned;
  • publish a GitHub Release with those assets and an auto-generated changelog;
  • push the Homebrew cask bump to homebrew-hadron-cli, so brew upgrade --cask hadron picks it up.

The cask push uses the HOMEBREW_TAP_TOKEN repo secret (a token with write access to the tap). If a release fails at the cask step, that token has expired or lost access — rotate it; nothing else needs a secret beyond the workflow's GITHUB_TOKEN (cosign signing is keyless — no secret).

macOS signing (notarization)

goreleaser codesigns (Developer ID Application) and notarizes the macOS binaries via quill, which runs on the Linux runner — no macOS runner needed. It's gated on the signing secrets being present, so releases keep working unsigned until they're configured. Until then the Homebrew cask strips the Gatekeeper quarantine flag on install; once notarized releases are verified, that strip is removed (#158).

To enable it, you set up five repository secrets — two from a signing certificate, three from a notary API key. One-time setup (an Apple Developer account is required); do it on a Mac, ~15 minutes.

Part 1 — the signing certificate → MACOS_SIGN_P12, MACOS_SIGN_PASSWORD

goreleaser signs with a Developer ID Application certificate. What it needs is a .p12 file bundling the certificate and its private key, base64-encoded.

  1. Create the certificate. In the Apple Developer portal, Certificates → +, choose Developer ID Application. When asked which intermediate, pick G2 Sub-CA (the current one). It has you upload a CSR — generate that with Keychain Access → Certificate Assistant → Request a Certificate from a Certificate Authority (save to disk). That creates the matching private key in your login keychain — essential; don't delete it. Download the issued developerID_application.cer.

  2. Import it into the login keychain (not System, not iCloud). Drag the .cer onto the login keychain in Keychain Access's sidebar, or double-click and choose login if prompted. The cert must land in the same keychain as its private key, or the .p12 export won't be possible.

    "This certificate is not trusted" is expected and harmless — it only means the Apple intermediate isn't installed locally; signing and notarization validate against Apple's servers regardless. To clear it, download Developer ID - G2 from https://www.apple.com/certificateauthority/ and double-click it. Do not set a manual "Always Trust" override — that breaks codesign.

  3. Export the .p12. Select the login keychain → My Certificates. Find Developer ID Application: … — it must have a ▸ disclosure triangle revealing a private key underneath (the "My Certificates" category only lists certs whose key is present). Right-click that row → Export → format Personal Information Exchange (.p12) → save and set an export password.

    Export greyed out? The cert and key are in different keychains (usually the cert got imported into System). Redo step 2 into login.

  4. Turn it into the two secrets:

    base64 -i "Developer ID Application.p12" | pbcopy   # copies to clipboard
    
    • MACOS_SIGN_P12 — paste that base64 blob
    • MACOS_SIGN_PASSWORD — the export password from step 3
Part 2 — the notary API key → MACOS_NOTARY_* (three secrets)

Notarization authenticates to Apple with an App Store Connect API key — separate from the certificate.

  1. In App Store ConnectUsers and Access → Integrations → App Store Connect API → Team Keys, click +, name it, role Developer, Generate.
  2. Copy the Issuer ID (a UUID, shown above the table) and the row's Key ID, and Download the AuthKey_XXXXXXXXXX.p8 (downloadable once — keep it).
  3. Turn them into the three secrets:
    base64 -i AuthKey_XXXXXXXXXX.p8 | pbcopy             # copies to clipboard
    
    • MACOS_NOTARY_ISSUER_ID — the Issuer ID (UUID)
    • MACOS_NOTARY_KEY_ID — the Key ID
    • MACOS_NOTARY_KEY — paste that base64 blob
Part 3 — add the secrets to GitHub

For each of the five: repo Settings → Secrets and variables → Actions → New repository secret, enter the exact name above, paste the value, save. The next tagged release then signs + notarizes automatically — nothing else to flip (the config is gated on all five being present).

Maintenance: the Developer ID certificate expires (~5 years) — a release starts failing when it lapses, so renew and re-export the .p12 then. Windows codesigning (a separate EV-cert lift) is out of scope.

Verify from the Actions run, the new release, and the goreleaserbot cask commit in the tap.

Architecture notes

  • Auth (v1): OAuth authorization-code + PKCE with a loopback redirect on 127.0.0.1. The server matches redirect URIs exactly, so each login binds the port first and registers a fresh public client via dynamic client registration. The resulting token is a long-lived hdr_user_* personal access token (no refresh tokens in v1). Stored in the OS keychain, falling back to ~/.config/hadron/auth.json (0600). A device-flow strategy can slot in behind internal/auth.Strategy once the server supports RFC 8628.
  • Output: commands marshal explicit DTOs, never generated GraphQL structs, so --json shapes stay stable across schema regenerations.
  • Exit codes are documented contract — see hadron agentic-usage.

Hadron slash commands (separate plugin)

The Hadron Claude Code slash commands — /hadron:h-task, /hadron:h-search, /hadron:h-open-node — live in their own marketplace, hadron-memory/hadron-plugins, so they're available without the CLI:

/plugin marketplace add hadron-memory/hadron-plugins
/plugin install hadron@hadron

Directories

Path Synopsis
cmd
hadron command
internal
api
Package api wraps the Hadron GraphQL endpoint: a genqlient client for typed operations, a raw escape hatch for `hadron api`, and the mapping from transport/GraphQL errors to exit codes.
Package api wraps the Hadron GraphQL endpoint: a genqlient client for typed operations, a raw escape hatch for `hadron api`, and the mapping from transport/GraphQL errors to exit codes.
api/gqltypes
Package gqltypes holds hand-authored Go types that the generated genqlient client binds to (see genqlient.yaml `bindings`).
Package gqltypes holds hand-authored Go types that the generated genqlient client binds to (see genqlient.yaml `bindings`).
auth
Package auth implements `hadron auth login` flows against the Hadron OAuth endpoints (spec 025: authorization-code + PKCE, public client via dynamic client registration).
Package auth implements `hadron auth login` flows against the Hadron OAuth endpoints (spec 025: authorization-code + PKCE, public client via dynamic client registration).
auth/store
Package store persists the Hadron access token, preferring the OS keychain and falling back to a 0600 file when no keychain is available (CI containers, headless boxes).
Package store persists the Hadron access token, preferring the OS keychain and falling back to a 0600 file when no keychain is available (CI containers, headless boxes).
build
Package build holds version metadata stamped at build time via -ldflags (see Makefile and .goreleaser.yaml).
Package build holds version metadata stamped at build time via -ldflags (see Makefile and .goreleaser.yaml).
cmd
Package cmd assembles the hadron command tree and owns the single error → exit-code → rendering path.
Package cmd assembles the hadron command tree and owns the single error → exit-code → rendering path.
cmd/access
Package access implements `hadron access` — inspecting who can do what.
Package access implements `hadron access` — inspecting who can do what.
cmd/agent
Package agent implements `hadron agent ...` — agent lifecycle management.
Package agent implements `hadron agent ...` — agent lifecycle management.
cmd/agentic
Package agentic implements `hadron agentic-usage` (D8): a single document an agent can read to learn the CLI.
Package agentic implements `hadron agentic-usage` (D8): a single document an agent can read to learn the CLI.
cmd/aiconfig
Package aiconfig implements `hadron ai-config ...` — the AI service config surface.
Package aiconfig implements `hadron ai-config ...` — the AI service config surface.
cmd/apicmd
Package apicmd implements `hadron api`, the raw GraphQL escape hatch (same role as `gh api`).
Package apicmd implements `hadron api`, the raw GraphQL escape hatch (same role as `gh api`).
cmd/app
Package app implements `hadron app ...`.
Package app implements `hadron app ...`.
cmd/auth
Package auth implements `hadron auth ...`.
Package auth implements `hadron auth ...`.
cmd/chat
Package chat implements `hadron chat ...` — a token-lean surface for AI agents (and humans) participating in a Hadron team-chat memory (see the how-to guide "Set up an agent team chat").
Package chat implements `hadron chat ...` — a token-lean surface for AI agents (and humans) participating in a Hadron team-chat memory (see the how-to guide "Set up an agent team chat").
cmd/configcmd
Package configcmd implements `hadron config ...`.
Package configcmd implements `hadron config ...`.
cmd/connection
Package connection implements `hadron connection ...` — management of a user's external connections (email/calendar) and the scoped grants that delegate access on them to Apps (spec-042; hadron-server #593/#599).
Package connection implements `hadron connection ...` — management of a user's external connections (email/calendar) and the scoped grants that delegate access on them to Apps (spec-042; hadron-server #593/#599).
cmd/edge
Package edge implements `hadron edge ...` — directed, labeled connections between two nodes.
Package edge implements `hadron edge ...` — directed, labeled connections between two nodes.
cmd/grant
Package grant implements `hadron grant ...` — individual action grants (design:grant-model; hadron-server #615).
Package grant implements `hadron grant ...` — individual action grants (design:grant-model; hadron-server #615).
cmd/mcpserver
Package mcpserver implements `hadron mcp-server ...` — the external MCP server registry (hadrontool-mcp conduit; hadron-server #634).
Package mcpserver implements `hadron mcp-server ...` — the external MCP server registry (hadrontool-mcp conduit; hadron-server #634).
cmd/memory
Package memory implements `hadron memory ...`.
Package memory implements `hadron memory ...`.
cmd/node
Package node implements `hadron node ...`.
Package node implements `hadron node ...`.
cmd/object
Package object implements `hadron object …` — the CLI surface for the object store (cor:api:170, server #745).
Package object implements `hadron object …` — the CLI surface for the object store (cor:api:170, server #745).
cmd/org
Package org implements `hadron org ...` — organization and membership management.
Package org implements `hadron org ...` — organization and membership management.
cmd/replacecmd
Package replacecmd implements `hadron replace`, bulk search-and-replace across many nodes (the CLI mirror of the MCP tool hadron_replace_globally).
Package replacecmd implements `hadron replace`, bulk search-and-replace across many nodes (the CLI mirror of the MCP tool hadron_replace_globally).
cmd/run
Package run implements `hadron run ...` — the headless App-run audit and control surface (spec-040, cor:agt:010:02).
Package run implements `hadron run ...` — the headless App-run audit and control surface (spec-040, cor:agt:010:02).
cmd/schedule
Package schedule implements `hadron schedule ...` — recurring headless-run triggers (spec-040, cor:agt:010, D-2026-07-04-E).
Package schedule implements `hadron schedule ...` — recurring headless-run triggers (spec-040, cor:agt:010, D-2026-07-04-E).
cmd/secret
Package secret implements `hadron secret ...` — management for the owner-scoped, encrypted secret store.
Package secret implements `hadron secret ...` — management for the owner-scoped, encrypted secret store.
cmd/spec
Package spec implements `hadron spec ...` — an opinionated layer over the generic node/edge commands for maintaining product-spec nodes that follow the loc-as-citation convention: a spec's loc IS its citation number, <module>:<feature>:<rule>:<flow> (e.g.
Package spec implements `hadron spec ...` — an opinionated layer over the generic node/edge commands for maintaining product-spec nodes that follow the loc-as-citation convention: a spec's loc IS its citation number, <module>:<feature>:<rule>:<flow> (e.g.
cmd/ticket
Package ticket implements `hadron ticket ...` — the action-ticket ledger (spec-040, cor:acl:050:04 tier 2).
Package ticket implements `hadron ticket ...` — the action-ticket ledger (spec-040, cor:acl:050:04 tier 2).
cmd/user
Package user implements `hadron user ...` (look up other users) and `hadron profile ...` (the signed-in user's own profile).
Package user implements `hadron user ...` (look up other users) and `hadron profile ...` (the signed-in user's own profile).
cmd/version
Package version implements `hadron version`.
Package version implements `hadron version`.
cmd/webhook
Package webhook implements `hadron webhook ...` — inbound webhook triggers for headless runs (spec-040, D-2026-05-02).
Package webhook implements `hadron webhook ...` — inbound webhook triggers for headless runs (spec-040, D-2026-05-02).
cmdutil
Package cmdutil provides the Factory injected into every command: lazily-resolved config, token store, and API client, plus the values of the persistent --json/--server/--app flags.
Package cmdutil provides the Factory injected into every command: lazily-resolved config, token store, and API client, plus the values of the persistent --json/--server/--app flags.
config
Package config reads and writes ~/.config/hadron/config.toml.
Package config reads and writes ~/.config/hadron/config.toml.
exitcode
Package exitcode defines the hadron CLI's stable, documented exit codes.
Package exitcode defines the hadron CLI's stable, documented exit codes.
nodedoc
Package nodedoc is the codec for a single node's portable file form — the frontmatter-markdown (and canonical JSON) representation that `hadron memory export`, `hadron node export`, and `hadron node import` all share.
Package nodedoc is the codec for a single node's portable file form — the frontmatter-markdown (and canonical JSON) representation that `hadron memory export`, `hadron node export`, and `hadron node import` all share.
output
Package output renders command results as human-readable text or JSON.
Package output renders command results as human-readable text or JSON.
urlsec
Package urlsec holds the URL-scheme security primitives shared by the API transport guard (which refuses to put a bearer token on a cleartext wire) and the OAuth login flow (which validates server-controlled discovery endpoints before handing them to the OS URL-opener or sending a token to them).
Package urlsec holds the URL-scheme security primitives shared by the API transport guard (which refuses to put a bearer token on a cleartext wire) and the OAuth login flow (which validates server-controlled discovery endpoints before handing them to the OS URL-opener or sending a token to them).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL