@fatelabs/estelle

中文文档
0.4.6发布于 2026/10/29Apache-2.0零依赖构建来源已验证近 30 天下载 2032

The trust layer under your AI coding agents. Estelle grounds every model in your real codebase and refuses to ship what isn't true: repository memory, a deterministic grounding gate, and grounded review. Model-agnostic, BYOK.

原始使用文档
文档目录7 节
  1. Install
  2. Two doors, and the difference between them
  3. What the CLI does
  4. What is measured
  5. Bring your own key
  6. Requirements
  7. How the install is verified

Estelle

The trust layer under your AI coding agents. Estelle grounds every model in your real codebase and refuses to ship what isn't true.

It is not another agent. It runs underneath the agents you already use and gives them three things they do not have on their own: memory of your repository, a deterministic gate that resolves every symbol a change names against your real code, and grounded review. Model-agnostic, bring your own key.

Install

curl --proto '=https' --tlsv1.2 -fsSL \
  https://github.com/uqeu/estelle-cli/releases/latest/download/install.sh | sh

That is the whole install. It puts the native estelle binary in ~/.local/bin.

This npm package is a launcher for the same binary, for machines that are already npm-based:

npm install -g @fatelabs/estelle

Either way you get one binary. See How the install is verified for what the launcher checks before it puts anything on your disk.

On npm 12 the install script is blocked, and that is fine. npm 12 refuses package lifecycle scripts by default, and this package's postinstall is what fetches the native binary — so npm install prints install scripts blocked and leaves nothing to run. The launcher handles it: the first time you run estelle, it performs the same checksum-verified download itself and then runs the binary. You will see one progress line, once. If that download cannot run — offline, a proxy, a 403 — the launcher tells you why and prints the repair, and any one of these does it:

npm install -g @fatelabs/estelle --allow-scripts=@fatelabs/estelle
node "$(npm root -g)/@fatelabs/estelle/install.js"
curl --proto '=https' --tlsv1.2 -fsSL \
  https://github.com/uqeu/estelle-cli/releases/latest/download/install.sh | sh

Set ESTELLE_SKIP_DOWNLOAD=1 if you would rather the launcher never reach the network; it then goes straight to that message. When the package directory is not writable by you — the usual result of a sudo npm install -g — the binary lands in ${XDG_CACHE_HOME:-~/.cache}/estelle/v<version>/ instead, which ESTELLE_CACHE_DIR overrides.

Two doors, and the difference between them

Both doors reach the same hosted server at https://api.fatelabs.ca/mcp. They do not see the same code.

Door 1: the plugin. Use this one. In Claude Code:

/plugin marketplace add uqeu/estelle-cli
/plugin install estelle@fatelabs

The plugin ships the hooks and the server entry together. The hooks fire on every edit rather than when the model decides to call a tool, and they send your working tree as you edit it, so uncommitted work is indexed. The plugin carries no credential: the client negotiates OAuth in the browser. The hooks shell out through npx, so Node 18 or newer has to be on the machine.

Door 2: the remote MCP URL. For hosts that cannot run a Claude Code plugin:

claude mcp add --transport http estelle https://api.fatelabs.ca/mcp

estelle init writes the same entry for every editor it finds, so you do not have to paste it once per tool.

This door has no hooks. It sees only what you have pushed, so its graph is never fresher than your last push to GitHub. If you are asking about code you wrote in the last ten minutes, use door 1.

What the CLI does

Ground a question in your actual repository.

estelle sweep                 # index this repo into your memory
estelle ask "how does billing retry a failed charge?"

Answers cite the files and lines they came from. When Estelle cannot ground an answer, it says so instead of inventing one.

Check a change before it merges.

estelle verify src/http/headers.rs    # resolve every symbol against the repo's real symbol graph
estelle gate                          # run that check over a local diff

Run on every edit, rather than when a model chooses to call a tool.

estelle install-hooks

Writes ten handlers across seven events (PreToolUse, PostToolUse, UserPromptSubmit, SessionStart, Stop, PreCompact, SessionEnd), for both Claude Code and the Codex CLI. This is door 1's mechanism, available to editors that are not Claude Code.

Every hook fails silently by design: no credentials, no network, a slow server or an empty memory all produce nothing rather than an error on the hot path. The UserPromptSubmit handler is still the slowest one, and it is now bounded. It used to ask the server for a full search and read only the recall text, paying for a code branch it discarded unread — measured at 133.4 s against 8.4 s for the same recall, byte for byte. It now asks for the one field it reads, and gives up at 20 seconds, ten seconds under the host's 30-second kill, because being killed by the host discards your prompt along with the hook's answer. The floor is the server's, not ours: POST /search has an observed floor near 6 seconds, so a prompt still costs that much before the model sees it, and if the budget expires the turn proceeds with no added context. Nothing tells you that happened.

What the edit hook does, exactly. It grounds the edit and reports one of four verdicts to you and to the model: PASSED, FLAGGED, ABSTAINED, or UNREACHABLE. ABSTAINED says in its own words that it is not a pass. It does not block the edit. The finding is advisory while the server does not attest index freshness, and the runner says so in the text it emits. The blocking check is estelle gate, which returns a merge verdict you can fail a build on.

And the edit hook inspects Python only today. A write to any other file type produces no output at all, so on that path "not checked" and "clean" look the same. Use estelle gate on the diff if you need a verdict for another language, and read the language scope under "What is measured" below.

Reach the assistants that have no hook runtime — 24 of them.

estelle install --list      # every host, and the exact path each one is reached at
estelle install --user      # install into every assistant this machine actually runs
estelle install --host cursor --project   # or name one, and write it into this repo
estelle uninstall           # take it back out of every host, both scopes, in one command

Hooks are one of two mechanisms and they are not interchangeable. Claude Code and Codex run a command before a tool call; Cursor, Copilot, Windsurf, Cline, Junie, Goose, Qwen, Kiro, Devin, Factory Droid, Amp, opencode, Kimi Code, Kilo, Trae, Antigravity and anything that honours AGENTS.md read a persistent instruction file instead, and a hook reaches none of them.

--user is the one that matters. An instruction file lives inside a repository, so it reaches nobody until that repository is opened. A user-profile install is loaded by the host itself on every session, before you have chosen a project, and costs nothing per turn. With no --host it installs only into assistants whose own config directory exists on this machine, so it reaches what you use and nothing else. Claude Code and Goose also get a SKILL.md in their native skill directory.

--project writes into the repository instead; naming neither does both. Every path here was read out of that host's own documentation — hosts whose path could not be established are deliberately absent rather than guessed at, and named in tui/src/host_table.rs.

Writes are additive and idempotent: your file keeps every byte it had, Estelle's block goes in delimited markers, the original is copied to .bak first, and a file that cannot be parsed is refused rather than overwritten. Running it twice changes nothing.

uninstall removes that block and nothing else. A file that held only Estelle's bytes is deleted outright with no .bak — there is nothing of yours in it — and the directories the install created go with it. ⚠️ That last part removes any directory left EMPTY, which it cannot distinguish from an empty one you made yourself; remove_dir refuses anything with content in it, so nothing you have written is ever at risk.

Serve any other harness.

estelle mcp-server            # Estelle's tools over MCP, for any agent
estelle acp                   # Agent Client Protocol, over stdio

estelle --help lists every command. A few worth knowing early:

estelle setupconfigure, brief, sweep, then prove Estelle on a real symbol from your repo
estelle initwrite the MCP entry for every editor you have installed
estelle doctorcredential and runtime readiness, reported without printing a secret value
estelle recallsearch your memory and your code together
estelle researchwatch a dependency for API drift, and propose a repair when it moves
estelle monitorproduction health, in the terminal
estelle githublink GitHub, connect an installation, and sweep a repository

What is measured

Estelle's grounding gate caught 38,153 of 38,153 invented APIs, with 0 false positives on 6,933 real symbols, over 45,086 labelled cases. It makes no model call: it parses the change and resolves each symbol against your repository's indexed symbol graph, so the verdict is a property of the artifact rather than a score that moves between runs.

Read the limit in the same breath, because it is the part that decides whether the number applies to you:

  • That measures invented repository APIs, in Python. A case is one code reference naming a repository symbol or import your codebase does not define.
  • Twelve of twenty-three supported languages block at some rung. Python is the only one with the full guarantee of existence, arity, type, and member calls on any receiver. The other eleven languages are navigated, not gated: their references are excluded from the rate rather than counted as passes.
  • It is not a correctness claim. Code can be perfectly grounded and still wrong. The gate tells you a symbol exists, not that the change does what you meant.
  • The eval harness is not in this public repository, so you cannot re-run it from here. What you can check from here is the behaviour, on your own code, with estelle verify and estelle gate.

Bring your own key

Estelle routes to whichever model you configure. estelle login --provider <name> knows fourteen: a Claude subscription, Anthropic, OpenAI, Google Gemini, GitHub Copilot, Azure OpenAI, AWS Bedrock, OpenRouter, DeepSeek, Fireworks, MiniMax, LM Studio, Ollama, and any OpenAI-compatible endpoint, which covers a model running on your own hardware. Your key, your provider, your bill. Estelle owns the routing, the grounding, and the memory. It does not own your model.

Fixes are proposed, not merged. The default writes to a sandbox and opens a pull request a human reviews. Auto-merge is opt-in, off by default, and gated on the fix being proved green in a sandbox first. There is no auto-deploy step.

Requirements

macOS or Linux on arm64 or x86_64, or Windows 10 (1803) or newer on x86_64. Node 18 or newer for this npm install path and for the plugin's hooks.

Windows is x64 only: there is no ARM64 Windows build, and the launcher says so by name rather than fetching an archive that does not exist. The Windows binary is estelle.exe with a statically linked C runtime, so it needs no Visual C++ redistributable. Its credential file (%USERPROFILE%\.estelle\auth.json) is protected by your user profile's ACL; POSIX 0600 modes do not exist on Windows. The local session server (estelle serve / connect) uses a Unix-domain socket, which Windows supports from 10 (1803). CI on Windows drives login, the hook runtime (hook stream included), sweep, mcp-server and install-hooks through the real binary; the interactive terminal UI and the session server compile for Windows but are not exercised there. The first release with a Windows archive is the first one cut after v0.4.2; earlier versions refuse win32.

How the install is verified

install.js does the work — run by postinstall on npm 10 and 11, and by the launcher on first use when npm 12 blocked that script. It is the same code and the same checks on both paths:

  • downloads over HTTPS only, from github.com or release-assets.githubusercontent.com and nowhere else. A redirect that leaves those hosts aborts the install.
  • bounds every download before taking it: 64 KiB for the manifest, 512 MiB for the archive, 5 redirects, a 30 second idle timeout, and a 5 minute wall-clock bound per request — because an idle timeout alone does not bound a server that dribbles one byte at a time.
  • requires the release's SHA256SUMS manifest to name your archive exactly once, with a well-formed 64-hex digest.
  • compares the archive's SHA-256 against that digest, and installs nothing on a mismatch.
  • requires the archive to contain exactly one member named estelle, and rejects any archive carrying unexpected members.
  • refuses a binary that is not a regular file, or that is a symlink.
  • stages into a temporary directory and moves the verified binary into place atomically.

The shell installer performs the same checksum and single-member checks. Both are mutation-tested in CI: a corrupted archive and an archive carrying an extra member must both be refused.

Every release is built by GitHub Actions, which publishes a signed SLSA build provenance attestation for each artifact. Neither installer checks that attestation for you, so verify it yourself if you want the stronger guarantee:

gh attestation verify estelle-<target>.tar.gz --repo uqeu/estelle-cli

This package is published with npm provenance. The binaries themselves are not code-signed or notarized.


fatelabs.ca · docs · install guide · Apache-2.0

版本与发布记录

@fatelabs/estelle 共发布 54 个版本,首次发布于 2026/07/30;过去 12 个月发布了 54 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.4.6latest2026/10/2916 天前
0.4.52026/10/2718 天前
0.4.42026/10/2718 天前
0.4.32026/10/2421 天前
0.4.22026/10/2421 天前
0.4.12026/10/2322 天前

关于 @fatelabs/estelle 的常见问题

@fatelabs/estelle 是什么?

The trust layer under your AI coding agents. Estelle grounds every model in your real codebase and refuses to ship what isn't true: repository memory, a deterministic grounding gate, and grounded review. Model-agnostic, BYOK.

如何安装 @fatelabs/estelle?

在项目目录运行 npm install @fatelabs/estelle,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 estelle,可以用 npx estelle 直接运行。

@fatelabs/estelle 支持 TypeScript 吗?

该包的 package.json 没有声明类型入口。需要类型提示时,可以在 npm 上查找社区维护的 @types/fatelabs__estelle 是否存在。

@fatelabs/estelle 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=18。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@fatelabs/estelle 可以商用吗?

@fatelabs/estelle 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@fatelabs/estelle 的下载量有多少?

根据 npm 官方下载统计,@fatelabs/estelle 在 2026/10/15 – 2026/11/13 这 30 天内被下载 2,032 次,日均约 68 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@fatelabs/estelle 还在维护吗?

最新版本 0.4.6 发布于 2026/10/29(16 天前);至今共发布 54 个版本,其中过去 12 个月发布了 54 个;首次发布于 2026/07/30。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。