mirror of
https://github.com/nearai/ironclaw.git
synced 2026-09-03 08:06:01 +08:00
* docs: stop publishing internal engineering docs to the public site
docs/.mintignore only excluded plans/ and internal/, so docs/reborn/,
superpowers/, qa/, adr/ and architecture-video/ were shipped to the
public Mintlify site. 33 internal architecture documents were live and
serving full content on docs.ironclaw.com, including the entire
reborn/contracts/ freeze set (kernel-boundary, secrets, capabilities,
trust-boundary-hardening, network, ...), the current architecture map,
and the product-manager architecture guide.
Verified by probing all 139 internal doc paths against the live site:
33 returned HTTP 200, 94 returned 404. The 404s were not protected by
policy -- they are simply newer than the last build -- so superpowers/
and the rest were exposed to the same leak on any rebuild.
Files stay where they are so they keep versioning with the code and
stay reachable by the knowledge graph; only publication changes.
No navigation page lives under a newly ignored path, so the public
site's page set is unchanged.
* docs: rewrite get-started pages against the shipped binary
The quickstart told users to start the agent by running `ironclaw` with
no arguments. The shipped 1.0.0-rc.1 binary requires a subcommand and
exits with code 2 and a usage error, so step 2 could not succeed.
Verified against the released binary rather than the source tree:
- install -> `ironclaw onboard` -> `ironclaw serve` is the real path;
onboarding prints a `login_link` with the web token
- onboarding writes config.toml, providers.json, webui-token and
.onboard-completed.json under ~/.ironclaw/reborn, and provisions the
master key in the OS keychain
- `serve` listens on 127.0.0.1:3000 and takes --host/--port
- real onboard flags are --force/--dry-run/--no-service/--import-history,
and --import-history is not wired up yet
Also drops the v1 onboarding steps that no longer exist (database
backend picker, embeddings toggle, tunnel/channel wizard, Docker
sandbox prompt), removes the stale PID-file troubleshooting for a
codepath the Reborn binary does not have, fixes the /channels and
/capabilities/jobs links on the index page, and corrects the provider
count from "7+" to 25+.
Removes the /home/agent and /home/user absolute paths flagged by
.claude/rules/doc-hygiene.md.
* docs: document the web interface, CLI, service, and Trace Commons
None of the shipped binary's primary surfaces had a page. The site
documented an agent you configure with environment variables and talk
to in a terminal; the product is a web application you start with
`ironclaw serve` and administer from the browser.
Adds four pages, all written from the verified 1.0.0-rc.1 command tree
rather than the source tree:
- using/webui: serve flags and defaults (127.0.0.1:3000), the
webui-token login link, Google/GitHub SSO env vars, and the visible
surfaces. Notes that sessions carry user identity only and do not
inherit operator config privileges.
- using/cli: the full command surface. Flags `channels list`,
`hooks list` and `logs` as registered-but-unimplemented so readers
do not file bugs against known stubs.
- using/service: launchd/systemd unit naming, log paths under
~/.ironclaw/reborn/logs, and the headless master-key note.
- capabilities/traces: the Trace Commons opt-in, preview/submit/revoke
flow, and instance enrollment. Calls out that bare `traces opt-out`
on an enrolled instance disables the whole enrollment.
Documents only the SPA routes that are actually in the sidebar;
Projects/Jobs/Routines/Missions/Logs are registered but hidden while
their v2 APIs land, and the page says so rather than describing a
sidebar entry that is not there.
* docs: rewrite configuration and storage against the real config model
The configuration page documented a ~/.ironclaw/.env bootstrap layer
plus database-backed settings, and cited src/config/ as its source of
truth. src/ no longer exists. None of DATABASE_BACKEND, DATABASE_URL,
LIBSQL_PATH, LLM_BACKEND, HTTP_PORT or SECRETS_MASTER_KEY are read by
the shipped binary.
Rewritten from `ironclaw config list`, `config path`, `config init`
output and the generated config.toml on 1.0.0-rc.1:
- config.toml (selection) + providers.json (catalog) under
~/.ironclaw/reborn, both optional
- precedence: compiled defaults < config.toml < env < CLI flags
- secrets referenced by env var NAME; pasting a value is rejected at
parse time
- the six real boot profiles, flagged as a security boundary
- real key groups incl. budget.* and trigger_poller.*, neither of
which was documented anywhere
- IRONCLAW_REBORN_* override namespace
Storage: the page claimed PostgreSQL is the default and that starting
without DATABASE_URL fails. The shipped StorageBackend enum has one
variant, Postgres, and local-dev stores state in embedded database
files with no server at all. Rewritten around that, keeping the
pgvector setup and adding the pool-sizing and sslmode=require notes
from the generated config comments.
Inference providers: the catalog is 26 built-in providers, not the 17
listed. OpenRouter, Together and Fireworks are first-class provider
ids rather than openai_compatible aliases, and Groq, DeepSeek,
Cerebras, SambaNova, Venice, NVIDIA, Z.AI, Tinfoil, native Gemini and
openai_codex were missing entirely. Every api_key_env in the table is
taken from providers.json. Also drops `ironclaw onboard
--provider-only`, which is not a real flag, in favour of
`ironclaw models set-provider`.
Deletes tunnel.mdx and zh/tunnel.mdx. Tunnels have no Reborn
implementation: no tunnel.* config key, no Rust source reference, and
the WebUI networking settings section is commented out. Removes the
now-dangling tunnel card from the channels overview.
* docs: cut channels to what the 1.0 binary actually supports
The site documented seven channels. The Reborn stack implements two.
Deleted, with no implementation in crates/:
- discord: appears only in comments and test fixtures as a
hypothetical future package
- signal: every match is a unix-signal or state-signal identifier,
not a messenger
- wechat / wecom: wechat survives only as the standalone
ironclaw_silk_decoder voice helper; wecom has zero references
- local: documented the v1 Ratatui terminal UI and web gateway with
GATEWAY_*/HTTP_* env vars. The real equivalents are `ironclaw repl`
and `ironclaw serve`, now covered under Using IronClaw.
- webhook: documented a standalone webhook channel with a shared
secret and HTTP_* config. No such config key exists; webhook ingress
now belongs to the extension host and serves Slack/Telegram events.
Telegram rewritten: the old page told users to run
`ironclaw onboard --channels-only`, which is not a real flag. Setup is
now WebUI channel setup plus the pairing step, with the real
/webhooks/telegram/updates callback.
Slack added. It has a first-party package, a v2 adapter, a [slack]
config section and a live /webhooks/extensions/slack/events route, and
had no page at all.
The overview says plainly that Discord, Signal, WeChat and WeCom were
v1 features and are not in 1.0, so readers who used them know to stay
on v1 rather than assume the docs are broken.
* docs: correct Responses API prerequisites and auth
The endpoints themselves are real and covered by
crates/ironclaw_reborn_composition/tests/webui_v2_serve.rs, but the
page's prerequisites were not.
- Drops the note requiring ENGINE_V2=true for external tools. Engine
v2 was removed; the only trace left in the tree is a stale comment.
Requests with tools[] no longer depend on a server flag.
- Replaces GATEWAY_AUTH_TOKEN and the self-service /api/tokens CRUD
surface, neither of which exists in crates/, with the real auth
paths: the onboarding-provisioned webui-token (or
IRONCLAW_REBORN_WEBUI_TOKEN) for single-user, and admin-minted
one-time per-user bearers via /api/webchat/v2/admin/users.
- Notes that the instance token is an operator credential while
per-user and SSO bearers carry user identity only, matching the
privilege split the gateway actually enforces.
* docs: replace extension commands that do not exist, consolidate MCP
Fourteen published pages taught commands the shipped binary does not
have. `ironclaw tool`, `ironclaw registry`, `ironclaw mcp` and
`ironclaw pairing` were v1 CLI subcommands; the Reborn CLI exposes
`ironclaw extension {search,install,activate,remove}` instead.
Rewrote the invocations across the Google suite, GitHub, web-search and
sandboxed-tools, and corrected the authorization prose: activating an
extension starts its setup flow, which is completed from Extensions in
the web interface, not from a CLI auth subcommand.
MCP had two pages, both built entirely on the nonexistent
`ironclaw mcp` CLI (add/list/test/toggle/remove/auth). Consolidated
into extensions/mcp and deleted capabilities/mcp, since MCP is a
runtime an extension declares rather than a capability of its own.
The stdio and Unix-socket transports the old page documented are not
supported: ironclaw_mcp rejects stdio outright ("unsupported until
process-level egress controls land"). The page now says HTTP only and
warns about stdio instead of giving instructions that cannot work.
Adds redirects for every page removed in this branch (capabilities/mcp,
tunnel, and the six retired channels) so existing inbound links land
somewhere useful instead of 404ing.
Full internal-link audit across all published English pages: 0 broken.
* docs: fix hosting guides and reconcile zh with the new structure
The three hosting tutorials ended with `ironclaw` as the start command,
so a reader who followed DigitalOcean, GCP or AWS end to end hit the
same usage error as the quickstart. They now run `onboard` then
`serve`, forward the port over SSH instead of exposing it, and install
the service so the agent survives disconnect.
Retires GATEWAY_AUTH_TOKEN (infrastructure/google, extensions/shell) in
favour of IRONCLAW_REBORN_WEBUI_TOKEN.
Chinese pages: deleted the two orphans that were never in navigation
(zh/capabilities/jobs, zh/extensions/google-calendar), applied the same
command corrections across 14 pages, and rewrote zh/channels/overview,
which still advertised Local, Signal, WeChat, WeCom, Webhook and Tunnel
as live cards pointing at deleted pages.
Full audit across all 76 navigation pages in both languages: 0 broken
internal links, no page missing from disk.
Left as follow-up: zh/quickstart, zh/onboard, zh/extensions/mcp and
zh/channels/telegram still mirror the pre-rewrite English structure and
need retranslation, not mechanical patching. They are flagged rather
than half-translated.
The /home/ironclaw paths in the hosting guides are deliberate — they
are the server-side service account, not developer-local paths, so
doc-hygiene does not apply to them.
* docs: address PR review, pinned to the released 1.0.0-rc.1 surface
These docs describe the version users can install today. Ground truth
is the `ironclaw-v1.0.0-rc.1` tag and the released binary, not `main`.
Two review findings were verified as main-only drift and deliberately
not applied:
- `ironclaw` with no subcommand. main added args_with_default_serve in
cb34f3769 so bare `ironclaw` starts the WebUI. At rc.1, `Cli.command`
is a required subcommand and the binary exits 2 with a usage error.
Kept the rc.1 behavior.
- `extension activate`. main removed it in 25ef441e7. rc.1 still ships
Search/Install/Activate/Remove, confirmed in the tagged source and in
the released binary's help. Kept it documented.
Both will need a follow-up pass when the tree main is on becomes the
released version.
Everything else from review applied after re-verifying against the tag:
- extension install takes an extension id, never a path or URL (true at
rc.1 as well) — rewrote the sandboxed-tools install flow, which had
inherited a v1 concept under a new command name
- Telegram: /webhooks/extensions/telegram/updates; both routes exist at
rc.1, and the documented setup goes through the Telegram extension
- only worker_count and the three concurrency caps have
IRONCLAW_REBORN_RUNNER_* overrides at rc.1; heartbeat_interval_secs
and poll_interval_ms are file-only
- openai_compatible needs base_url, present on the rc.1 slot type and
previously undocumented; noted that the LLM_* env blocks are the
supported fallback, not stale v1 syntax
- traces revoke is local-only without --endpoint; documented the real
flag and its IRONCLAW_TRACE_SUBMIT_TOKEN default
- foreground serve and the service both bind the port, so the
quickstart and all three hosting guides described a sequence that
fails; they now stop the foreground server first
- retired the last GATEWAY_HOST/GATEWAY_PORT (en + zh GCE guide) and
HTTP_WEBHOOK_SECRET (zh shell); neither exists at rc.1
- marked the unimplemented CLI stubs inline rather than contradicting
the table in a following note
- .mintignore: removed the claim that omission from navigation keeps a
page private. It does not, which is how 33 internal contracts were
served; .mintignore is the only publication boundary
- added the missing /zh/* redirects and retranslated zh/extensions/mcp
and zh/channels/telegram, which still carried `ironclaw mcp` and
`ironclaw pairing`
Separately found by auditing every documented invocation against the
rc.1 command list: extensions/github.md used `ironclaw secret set`,
which has never existed. There is no CLI alias for a GitHub PAT, so it
now points at the extension setup flow.
Validation: every `ironclaw ...` invocation in all 76 navigation pages
checked against the rc.1 command surface, 0 mismatches; 0 broken
internal links; 17 redirects resolving.
* docs: channel setup traps, OAuth redirect URIs, Slack manifest, hosted restart
Covers #6668 and #6671, plus the redirect URIs, Slack app manifest, and
hosted-instance configuration steps that were missing entirely.
Discoverability (#6668, #6671). Both issues are one failure from a
user's side: the working setup surface exists but is not where anyone
looks, and the two obvious routes to it dead-end. Verified against the
rc.1 frontend -- channels-tab.tsx renders the Slack and Telegram connect
cards *below* the web/webhook/CLI/REPL rows in the Built-in panel, and
extensions-page.tsx defaults `tab` to "registry". The real path is
Extensions -> Channels tab -> bottom of Built-in -> Configure, and
neither half of that is discoverable.
Documented where a stuck user lands: a "Where Channel Setup Lives"
walkthrough in channels/overview; the tab-and-scroll location on both
channel pages; a "What Onboarding Doesn't Set Up" section in onboard,
which was silent on channels; and troubleshooting entries keyed to the
literal error string and to "I asked the agent and it said it couldn't".
The Telegram page now separates the operator bot-token step from the
per-user pairing step. Conflating them is what makes "An administrator
must configure the Telegram bot first" read as a permissions problem
when it means "wrong tab".
Redirect URIs, each checked against the routes rc.1 serves:
- Slack events: /webhooks/slack/events
- Slack personal: /api/reborn/product-auth/oauth/slack_personal/callback
- Google: /api/reborn/product-auth/oauth/google/callback
with matching IRONCLAW_REBORN_* variables and exact-match warnings,
since a trailing-slash difference is a silent authorization failure on
both providers.
Fixes a bug this branch introduced: channels/slack.mdx used
/webhooks/extensions/slack/events, which rc.1 does not serve.
Google keeps both flows because both exist at rc.1 -- the fixed-port
loopback callback (ironclaw_auth/src/loopback_oauth.rs, 9876) and the
server-hosted callback -- and the page now says which is which. Also
retires GOOGLE_OAUTH_CLIENT_ID/SECRET, v1 names absent from rc.1, in
favour of `ironclaw config set google.*`.
Slack app manifest added, JSON-validated, using the full
/api/reborn/product-auth/... redirect path; a shortened form 404s.
NEAR AI hosted instances. Configure over SSH with `ironclaw config set
google.client_id` / `google.redirect_uri` / `google.client_secret`, then
restart from the Agent Dashboard -- `ironclaw service` shells out to
`systemctl --user`, which a hosted instance does not provide, so every
`service` subcommand fails there including `restart`. That limitation is
now called out on every page that recommends `service`: using/service,
using/cli, quickstart, onboard, configuration, and the Google OAuth
setup. `config set` never restarts anything itself -- it prints "to
apply: ironclaw service restart" and the old value keeps serving until
the instance is restarted.
Also corrects two invalid examples this branch introduced: `config set
runner.poll_interval_ms` and `config set webui.listen_port` are not
accepted -- `set` takes only the alias-table keys, while `list`/`get`
read everything. Those are edited in config.toml.
Mirrored into zh/channels/overview, zh/channels/telegram, and
zh/extensions/google/oauth-setup.
Docs only. The underlying UX defects stand: #6671 needs Registry's
Configure to branch to admin setup when the bot token is unset, and
#6668 needs the capability-description/prompt fix. Documenting the
workaround does not close either.
Validation on a local `mint dev` preview: `mint broken-links` clean,
all navigation pages render, every removed page redirects to its
replacement, and every internal doc (reborn/, superpowers/, plans/,
qa/, adr/, reborn-binary) returns 404 -- including
reborn/contracts/kernel-boundary, which is live on production today.
Every ironclaw invocation across all 76 pages checked against the rc.1
command surface: 0 mismatches.
* docs: second review pass — extension install shape, provider ids, tool discovery
Five review findings applied; one rejected as main-only drift.
Applied:
- `extension install` takes an extension id, never a path or URL. The
earlier mechanical rename left `./my-tool.wasm` and https:// examples
in zh/capabilities/sandboxed-tools and zh/extensions/building-a-tool.
Both now use search-then-install-by-id and say the path form fails.
- Tool discovery in capabilities/sandboxed-tools described the v1
`~/.ironclaw/tools/` and `<workspace>/tools/` directories, which do
not exist anywhere in rc.1 crates. Packages are discovered from
`/system/extensions/<id>/manifest.toml` through the Reborn runtime,
and a self-built package is imported from the WebUI rather than
dropped in a directory.
- llm-providers contradicted itself: the table gave Together and
Fireworks dedicated provider ids while the sections below still
configured them as LLM_BACKEND=openai_compatible. Both now use
`models set-provider`. The remaining openai_compatible examples are
vLLM/LiteLLM/LM Studio, which is what that provider is for.
- `config set <key> <value>` implied a value is always required;
secret-destination keys take none and prompt. Synopsis is now
`<key> [value]`.
Rejected, with evidence:
- "Slack Event Subscriptions should be /webhooks/extensions/slack/events".
That is the route on main, not at rc.1. rc.1 serves
/webhooks/slack/events; every /webhooks/extensions/* reference in the
tagged tree is Telegram. The route moved in 59afb4f9e (#6443), which
`git merge-base --is-ancestor` confirms is NOT an ancestor of
ironclaw-v1.0.0-rc.1. This is the third main-only drift on this PR,
after default-serve and extension activate.
Validation: 76 nav pages, 0 broken links, 0 unbalanced components, and
every ironclaw invocation still matches the rc.1 command surface.
* docs: stop advising an open firewall port for the SSH OAuth tunnel
The Google OAuth page told operators to whitelist port 9876 in the
server firewall "to allow the tunnel to work properly". That is both
unnecessary and a downgrade: `ssh -L 9876:127.0.0.1:9876` carries the
callback inside the existing SSH connection, so no inbound port is
opened, and whitelisting 9876 would expose the loopback OAuth callback
to the internet for no benefit.
Replaced the tip with a warning not to open the port, and reworded the
step so it explains what the tunnel is actually bridging: the callback
listens on loopback inside the server, the browser runs on the
operator's machine.
Pre-existing content, not introduced by this branch. Applied to the
English and Chinese pages.
* docs: drop the dead loopback OAuth flow, stop showing secrets in shell exports
The Google OAuth page documented two callback flows. Only one works on
the shipped binary.
`crates/ironclaw_auth/src/loopback_oauth.rs` — the fixed-port
127.0.0.1:9876 listener — says in its own header: "for the v1 (legacy)
stack only", "## Not used by Reborn", "The sole consumer is the root
`ironclaw` v1 binary", "## DELETE WITH V1". At rc.1 nothing outside
ironclaw_auth references OAUTH_CALLBACK_PORT or bind_callback_listener,
and the v1 binary is not shipped: the release contains only the Reborn
CLI. So the loopback redirect URI and the whole SSH-tunnel step were
instructions a reader could not complete.
This also resolves the inconsistency reviewers flagged: the page told
users to open an SSH tunnel for the loopback callback and then set
google.redirect_uri to the hosted callback, which would have produced a
redirect_uri_mismatch and made the tunnel pointless. There is now one
documented callback,
https://<host>/api/reborn/product-auth/oauth/google/callback, so the
two cannot drift apart.
Corrects my earlier claim on this PR that both flows exist at rc.1. The
module exists in the tree; it has no consumer in the shipped binary.
Secrets in shell history:
- Removed the interactive `export ...CLIENT_SECRET=` example from the
Google setup. The page already said prompted input avoids shell
history, then contradicted itself. Env vars are now listed by name
only, for service/container injection from a secret manager.
- Same caution added to the WebUI SSO section, where the variables are
real but the interactive export is not how they should be set.
- extensions/github used GITHUB_OAUTH_CLIENT_ID/SECRET, which do not
exist at rc.1 at all; credentials go through the extension setup flow.
Also rewrote the zh quickstart start step, which still told users to
delete a stale PID file and re-run bare `ironclaw` — a v1 codepath the
Reborn binary does not have. It now matches the English page.
No published page references port 9876, a retired env var, or a
nonexistent command. Validation: 76 nav pages, mint broken-links clean,
0 unbalanced components, 0 command mismatches against rc.1.
* docs: correct admin create-user response shape and Google redirect claim
Two review findings, both verified against rc.1.
The Responses API auth tab showed the admin create-user response as
`{"id":"...","api_token":"..."}`, implying a top-level `id`. The real
shape is `RebornAdminUserCreatedResponse { user: AdminUserRecord,
api_token: String }` — the token is top-level, the identity is nested
under `user`, and the id field is `user_id`. Confirmed in
admin_users.rs and in the frontend's own normalizer
(`{ ...normalizeUser(response?.user), token: response?.api_token }`).
Replaced the inline comment with a full response body so a reader
parsing it does not reach for the wrong field.
The Google OAuth page said "Google will not redirect to a loopback
address", which attributes an IronClaw constraint to Google. Google
does support loopback redirect URIs; the reason the hosted callback is
required here is that IronClaw's product-auth flow receives callbacks
on a gateway HTTP route and has no loopback listener. Reworded in both
languages to say that plainly.
* docs: fix commands and config claims that fail against rc.1
Six corrections found by review, each verified against the
ironclaw-v1.0.0-rc.1 tag rather than main:
- Web Search page documented a Brave Search API key and the extension
id `web-search`. Neither exists at rc.1: the extension is
`web-access` (Exa-backed) and needs no credentials at all — the
product's own onboarding copy says "Web Access does not need
credentials". Rewritten in EN and zh around the real setup.
- `traces opt-in`, `submit` and `enqueue` were shown without their
required `--endpoint` / `--envelope` flags, so the page's core
opt-in-then-contribute walkthrough could not be followed. Added them.
- `traces preview`, `enroll-instance`, `ingest-health` and `profile
set` were shown with positional args that are actually named flags
(`--recorded-trace`, `--invite`, `--endpoint`, `--handle`).
- `POST /admin/users` example omitted `role`, which has no serde
default and is therefore required; the request failed to deserialize
before creating anything.
- Claimed `identity.tenant` / `default_agent` / `default_project` are
rejected. `runtime_identity()` consumes the first two, and `serve`
consumes the third — only `run`/`repl` reject `default_project`.
- Told operators to pair `[storage]` with
`hosted-single-tenant-volume`, which is not one of the three profiles
that wire it, so the instance fails to boot. Reordered the steps so
the profile is set before `[storage]`, and corrected the profiles
table, which implied that profile is PostgreSQL-backed.
Five further review findings were declined: they describe main, not
rc.1 (bare `ironclaw` defaulting to serve, `extension activate` being
removed, the Slack ingress route move, the `slack_personal` provider
retirement, and its redirect-URI env var). All five are still the rc.1
behavior this branch documents.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>