With fd 2 dead (a closed pane, an exited pipe reader) every write fails,
eprintln! panics on that failure, and under panic = "abort" the process
dies by SIGABRT with a crash report on the next launch instead of its
exit code. Exit reports, headless plain-format diagnostics, update-exit,
setup-result and leader-management messages now write through
best_effort_stderr::eprint_line: one attempt, failure reported, never a
panic.
Ported from upstream 1.0.19 (grok-build best_effort_stderr.rs).
Claude-Session: https://claude.ai/code/session_01RUqV8HVGXcAETyYbZ2tPQ4
A terminal that stopped draining the pty parked the writer thread inside
its tty write while it held the stderr lock; the next inline stderr write
from the event loop (mouse toggle, notification, kitty clear) deadlocked
the loop, and /quit hung on the unbounded writer join and the teardown
writes.
EscapeWriter queues out-of-band escapes on the frame writer: the mouse
capture toggle, notifications (title, progress, protocol), the auth
cursor, gboom keyboard flags, the wrap clipboard request, and the kitty
clears (queued per agent view and merged into the frame's post-flush,
nested subagent views included). The $EDITOR/$PAGER handoff aborts when
the writer does not drain. WriterThread::join_within and the teardown
run under a 2 s grace; after a stall fd 2 is silenced, the exit hints,
relaunch and update prints are skipped, and the panic hook keeps only its
log report.
Ported from upstream 1.0.19 (grok-build EscapeWriter, WriterJoin,
run_bounded_teardown), extended to the remaining inline writes.
Claude-Session: https://claude.ai/code/session_01RUqV8HVGXcAETyYbZ2tPQ4
Port of upstream grok-build 0.2.113/0.2.114 fixes, extended to Kigi's
startup order.
- kigi-tty-utils runtime module: worker-cap policy (8 max) — tokio's
per-core default pins 100+ thread slots on many-core shared hosts
against RLIMIT_NPROC / pids.max, and later spawns die with EAGAIN.
- kigi-bin builds the main runtime with capped workers and reports an
out-of-threads host with a diagnostic + exit(1) instead of a panic.
- The pre-runtime optimization threads (HTTP warmup, early model
prefetch) spawn recoverably and degrade — their panic would have
preempted the runtime's own diagnostic.
- The per-session actor thread and its runtime report spawn/build
failure through the existing acp::Error / AgentBuildError boundaries
(new RuntimeBuild variant) instead of panicking the agent host.
- fsnotify's watcher thread spawn maps into FsNotifyError::WatcherStart
so callers degrade instead of crashing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KSy9S31pZNWXtRZNVJ1sDf
Sweep every first-party crate source (1956 .rs files) to the project comment
guidelines: delete redundant restatements, decorative banners, change
narration, and end-of-line comments; keep and tighten the crucial ones
(invariants, bug rationale, SAFETY blocks, ported-source attribution).
No functional code changed. Every edit is proven comment-only against the
prior tree by a comment-stripping lexer (string/char/raw-string aware) plus a
separate doctest-fence check. Where removing a comment made rustfmt or clippy
want to re-lay-out adjacent code, the minimal triggering comment is restored so
code tokens stay byte-identical.
Gates green: cargo fmt --all --check (0 diffs), cargo check and cargo clippy
--workspace --all-targets (0 warnings).
Adds scripts/check_codegen_comment_guidelines.py — the enforcement gate for
these guidelines (flags banners, end-of-line comments, change narration, and
commented-out code).
The PRD's first acceptance gate now holds: grep -RinE '\bx\.ai\b|grok'
crates/ --include='*.rs' → 0 matches (exempt: NOTICE and third-party
license archives, README provenance, and the required 'Based on Grok
Build Open Source' attribution, now sourced from version_attribution.txt).
Wire-visible renames (both sides in this repo, changed in lockstep):
- Auth method id 'grok.com' → 'kimi-code' (AuthMethodKind::KimiCode).
- Every x.ai/* and _x.ai/* ACP ext method and meta key → kigi/* /
_kigi/* (~200 names; grokShell → kigiShell). Session-file replay keeps
a read-side alias for the legacy '_x.ai/session/update' method so
existing updates.jsonl histories load; writes emit only the new name
(both directions test-pinned).
- Agent types grok-build* → kigi* with a documented legacy-prefix alias
at resolution time so persisted sessions keep resolving.
- ToolNamespace/BuiltinAgentName GrokBuild* → Kigi* (wire snake_case
kigi/kigi_concise/kigi_hashline; schema regenerated); grok_build
implementation dirs renamed to kigi*.
- x-grok-* headers → x-kigi-*, __GROK_* sentinels → __KIGI_*, themes
grokday/groknight → kigiday/kiginight (old persisted values fall back
to the default theme), web_fetch allowlist xAI hosts → kimi.com +
moonshot platforms, changelog CDN → this repo, grok-build changelog
archives deleted.
- BYOK default endpoint removed: [endpoints] api_base_url is now truly
optional with NO default — consumers fail fast with the flag name when
unset (no silent x.ai egress). Mock harnesses inject it explicitly.
- System-prompt identity fixed: 'released by xAI' → 'an unofficial
community CLI for Kimi' (template + regenerated encrypted form).
Also repaired pre-existing grok-era test debt found by the sweep: the
stale trace_classify default-model pin, the grok-pager UA label test,
pty-harness stale-binary reuse and non-hermetic moonshot routing (a PTY
test could previously reach the real api.moonshot.cn), and the outdated
oauth fixture scope key.
Gates: §9 grep 0; fmt clean; workspace check/clippy 0/0 (-D warnings);
FULL cargo test --workspace: 234 suites, 21,961 passed, 0 failed;
deny advisories ok.
- .github/workflows/release.yml: on tag v* build all 5 targets (macOS
arm64/x86_64, Linux arm64/x86_64 incl. free arm runners, Windows
x86_64) with the release-dist profile, archive kigi-<version>-<triple>
with LICENSE/NOTICE/THIRD-PARTY-NOTICES, generate SHA256SUMS, publish
the release (prerelease for tags containing '-'), with a tag↔workspace
version guard.
- install.sh / install.ps1 (repo root): platform detection, latest or
--version download from GitHub Releases, SHA-256 verification against
SHA256SUMS, install into the kigi home's downloads/ + bin/kigi symlink
(the same layout the self-updater manages), smoke test, PATH guidance.
- kigi-update rewritten onto the GitHub Releases API (documented wire
shape; stable=/latest, alpha=semver-max across the list, pinned=/tags):
SHA-256 gate before any binary swap, tar.gz/zip extraction per
platform, atomic bin/kigi symlink swap, channel/rollback semantics and
the KIGI_AUTO_UPDATE gate preserved verbatim; every x.ai/GCS/npm
endpoint deleted, npm/gh-release installers removed, legacy grok/agent
links retired on install. kigi-env owns the update base URL with a
KIGI_UPDATE_BASE_URL override (this is what the test artifact server
injects).
- .cargo/config.toml: removed the non-portable neoverse-v2 CPU pin on
Linux arm64 (fleet-specific); RELRO/NX hardening link-args now apply
to the gnu targets too, matching the release-dist profile's contract.
- THIRD-PARTY-NOTICES regenerated via cargo-about (about.toml +
template); the M0 hand-built file is dropped and README points at the
generated one. docs/RELEASE.md carries the release checklist.
- Deleted xAI-era leftovers: kigi-tui/scripts/install*.{sh,ps1} (x.ai
CDN) and the @xai-official/grok npm skeleton (PRD F8: no npm).
Gates: fmt clean; workspace check/clippy 0/0 (--locked, -D warnings);
kigi-update 58 lib + 86 integration tests green; deny ok;
release-dist build of kigi-bin succeeds and reports 'kigi 0.1.0'.
Removed root-and-branch for the zero-egress guarantee (the hub was xAI's
remote-workspace/cloud-sandbox service):
- Crates deleted: kigi-computer-hub-core, kigi-computer-hub-sdk,
kigi-computer-hub-mcp-adapter, kigi-workspace-client (hub-proxied
workspace RPC client), and kigi-tracing (its sole network path was the
OTLP gRPC exporter; zero consumers remained). kigi-tracing-macros
(purely local) stays.
- kigi-workspace: every hub surface deleted — hub server/channel/auth,
HITL-over-hub permissions, donation/metrics pumps, file upload RPCs,
hub tool-snapshot merge (resolve pipeline is MCP-only now),
WorkspaceOps::Proxy. Local worktrees, sessions, leader IPC, MCP, and
the ACP permission prompt path are untouched; LocalRegistry re-homed
into kigi-tool-runtime on the existing ToolDyn types so in-process
tool dispatch is unchanged.
- kigi-shell: leader workspace-exposure control surface (incl. the
wss://computer-hub... URL), [hub] config, ObservabilityBridge, hub
WebSocket proxy, dead OTLP config knobs. ClientMode::Headless (never
constructed) removed.
- kigi-tui/bin: hidden `kigi workspace` command removed (`kigi
worktree` stays).
- Renames: --xai-api-base-url → --api-base-url / KIGI_API_BASE_URL /
[endpoints] api_base_url (serde alias keeps old configs working; the
flag feeds BYOK/custom-endpoint routing, not main inference);
grok_version → kigi_version in inspect/models-cache/trace metadata
(old caches self-heal via version-mismatch refetch).
- Dependency tree: dropped fastrace*, opentelemetry-otlp/http/proto,
tokio-tungstenite from the workspace; fixed the 4 real useless_format
violations the fastrace lint allowance was masking and removed the
allowance.
- marketplaceAllowlist kept: it gates the LOCAL plugin-marketplace
feature, not an xAI service.
Known §9 leftover (deliberate, for the M3 sweep): the BYOK default base
URL string. Gates: workspace check/clippy 0/0, fmt, deny ok; suites
green (workspace 1042, shell 4918, tui 6634, tools 2608, tool-runtime
47, mcp 154).
New `kigi import-kimi` (with --dry-run) plus a one-time welcome-screen
hint when ~/.kimi/config.toml is present and unimported.
- Sources: ~/.kimi/config.toml (default_model, [models.*], [providers.*])
and ~/.kimi/mcp.json ({"mcpServers": ...} — parsed by the existing
McpConfig machinery). Shapes ported from kimi-cli 1.49.0 config.py with
citations.
- Strictly read-only over ~/.kimi: plain reads only; the test suite pins
byte-identical contents AND unchanged mtimes across scan+apply. Keyring
credentials are never imported; KIMI_SHARE_DIR / any KIMI_* env var is
never consulted (official dir hardcoded to ~/.kimi).
- Mapping: MCP servers merge into kigi [mcp_servers.*] without clobbering
existing names; models on non-built-in providers become kigi [model.*]
custom entries (base_url + api_key + context_window); providers that
duplicate kigi's built-in Kimi/Moonshot platforms are skipped with a
note; default_model maps to the imported alias or the managed catalog
key and never overwrites an existing default.
- One-time marker ~/.kigi/kimi_import_done (claude-import convention);
the startup hint and re-runs no-op once set. api_key values flow only
into the user's own config.toml and are redacted in every summary.
Verified end-to-end with the real binary in a sandboxed home: dry-run,
apply, `kigi mcp list` shows both imported servers, second run no-ops,
~/.kimi mtimes unchanged. 8 unit tests + CLI parse test.
- `kigi acp`: top-level alias for the stdio ACP server (kimi-cli `acp`).
AgentArgs.mode is now optional — bare `kigi agent` and `kigi acp` both
default to stdio at dispatch; `kigi acp <mode>` is rejected.
- `kigi mcp auth <name>`: authorize an OAuth-enabled remote MCP server
(kimi-cli `mcp auth`). Reuses the doctor's interactive connection path:
starts the named server with OauthInteractivity::Interactive (browser
flow when required), completes the handshake, and reports the tool
count. Stdio servers and unknown names fail with actionable errors.
- `--mcp-config-file <PATH>` (repeatable, global): extra MCP config files
in the .mcp.json shape ({"mcpServers": {...}}), kimi-cli semantics.
Files are validated at parse time (fail fast on unreadable/invalid
JSON), carried across the TUI -> shell boundary via
KIGI_MCP_CONFIG_FILES, and merged at HIGHEST priority — an explicitly
passed file overrides every config scope. Covered by loader unit tests
and verified live: an injected server surfaces in the session's
x.ai/mcp/servers_updated notification via both the flag and the env.
The stale bare-agent-requires-mode CLI test is re-contracted to the new
default-to-stdio behavior.
The headless not-signed-in message still pointed at `grok login` and
XAI_API_KEY; error copy across the shell (re-auth prompts, managed-config
rejection, mcp doctor, trace classifier) and kigi-bin did too. All now
reference `kigi login` / `kigi logout`, and the headless fallback points
at the Moonshot open-platform key (KIGI_MOONSHOT_API_KEY).
macOS ld cannot encode >16MB of __eh_frame in its compact unwind table and
says so on every debug link of the large binary. All profiles build with
panic=abort, so Rust never unwinds and the note's exception-handling caveat
does not apply. Allow rust.linker_messages at the workspace level with that
rationale, and give kigi-bin the missing [lints] workspace = true (it was
not inheriting workspace lints at all). Also drop the stale xAI authors
field and Grok wording from the kigi-bin manifest.
Sampler / inference (PRD F3):
- kimi_compat.rs: single adaptation point for the Kimi chat/completions
dialect (thinking-field mapping, model_id stripping, empty-content
tool-call message fix, stream_options.include_usage), with kimi-cli
source citations
- Rate-limit handling reworked for Kimi/Moonshot semantics; UA kigi/{version}
- /models replaces the xAI models-v2 endpoint everywhere; idle model
refresh carries X-Msh-* device headers only (X-XAI-Token-Auth and
x-grok-client-mode/CLIENT_MODE_HEADER machinery deleted)
Cloud-surface excision (PRD §5, zero-egress):
- remote/ conversations lane, cli-chat-proxy-types crate, prod/ dir,
share command, credit bar: deleted (single local session lane;
paginate() replaces merge_and_paginate)
- Subscription/tier gate stack deleted end-to-end: AppView
gate/tier/team/ZDR fields, app/subscription.rs watch loop,
dispatch/billing.rs paywall + SuperGrok upsell, free-usage-exhausted
chain, tier-restricted commands, GateInfo, RemoteSettings gate fields,
SettingsUpdateNotification gate fields
- /privacy + coding-data-sharing setting deleted (backed by a dead xAI
RPC; Kigi is zero-egress — nothing to share or retain remotely)
Auth UX correctness (user-reported):
- Device-flow fixtures now mirror the live Kimi payload shape
(https://www.kimi.com/code/authorize_device?user_code=..., verified
against auth.kimi.com); the fabricated auth.kimi.com/device?code=...
URLs are gone
- open_browser_detached is a no-op under cfg(test): unit tests drove
wiremock fixture URLs into the real browser (root cause of the
"garbage mock link" ABCD-1234 tabs)
- Welcome/pager-minimal rebrand: Grok Build -> Kigi, grok.com ->
kimi.com, "Sign in to Grok" -> "Sign in to Kimi"