candor

io.github.tombaldwin由 GitHub 账号 tombaldwin 发布v0.41.3更新于 Nov 8, 2026

Per-function effect analysis for agents: blast radius, what reaches the network, gate verdicts.

发布方自己的服务:Candor Finance

概览

AI 生成的概览

只读 MCP 服务器,基于预先算好的 candor 报告回答 TypeScript 项目问题:每个函数的副作用、调用图影响范围与架构策略判定。

可以做什么
  • 追踪调用图影响:反向影响范围、直接与传递调用者,以及到执行某效果函数的最短调用链
  • 梳理效果面:哪些函数直接或继承地执行 Net、Db、Exec、Fs 等效果,以及程序运行时实际可达什么
  • 查看结构:单个函数自身与继承的效果及字面 hosts、命令、路径、表,以及按模块的效果总览
  • 检查策略:假设性改动前的门禁判定、已提交策略的判定、边界修复建议,以及刷新 accept 行的提案
  • 诊断不确定性与漂移:各边界效果的分散度、按影响排序的 Unknown 来源,以及相对基线的按函数或供应链效果增量
  • 查看本地活动日志中记录的实测门禁活动
适用场景
当编码助手需要关于 TypeScript 代码库运行时效果的确定性答案、而不想手工追踪调用图时使用:评估一次改动的影响范围、找出哪些代码会访问网络或数据库,或判断改动能否通过仓库的架构策略。
运行要求
以 npm 包 candor-ts 形式在本地通过 stdio 运行,需要 Node.js,仅支持桌面客户端。必须已有由单独的 candor 扫描生成的报告,服务器本身从不扫描。报告位置来自每次调用的 report 前缀、CANDOR_REPORT 环境变量或默认的 .candor/ 目录;CANDOR_ROOT 可把服务器锁定到单一工作区。
安装前请注意
仅查询、只读:它读取报告文件,不扫描、不修改、不写入代码。答案描述代码“可能到达”什么而非“实际做了什么”,无法解析的调用会标为 Unknown 而非纯函数,因此干净的判定可能并不完整;应检查 ok 是否存在而非只看其值。基于报告计算的门禁只是建议性的,策略或基线无法读取时会报错而不会放行。

安装

在 SourceWeft 中

  1. 打开 控制台中的 candor,将其添加到工作区。
  2. 为需要使用其工具的对话启用该服务。

Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。

其他 MCP 客户端

参照 仓库 中的启动说明。

README

candor-ts

[Beaky, the candor canary]

candor for TypeScript: per-function side effects, transitively, with a deterministic policy gate. candor-ts resolves every call through the TypeScript compiler API and reports, for each function in your project, which effects it can reach — Net, Fs, Db, Exec, Env, Clock, … — including effects inherited through any chain of calls across files, with a disclosed Unknown wherever resolution fails (a callback value, an any-typed callee — never silently pure). A candor-spec implementation, sibling of the Rust and JVM engines.

Site: candor.poly.io — the measured case in five minutes.

sh
npm install   # typescript + @types/node
node scan.mjs <project-dir>                 # tsconfig.json honored; tests excluded; writes                                            #   <dir>/.candor/report.json + .callgraph.jsonnode scan.mjs . --policy .candor/policy     # the §6.2 gate: exit 1 on violation, 2 if unreadablenode scan.mjs . --gate-json gate.json       # + the structured verdict {spec, ok, violations} (§3.3)CANDOR_BASELINE=saved.json node scan.mjs .  # AS-EFF-005 guard: exit 1 if an existing fn GAINED an                                            #   effect vs the saved report; 2 if it can't evaluate
node scan.mjs --version                     # installed build + spec contract (offline), + upgrade line
node query.mjs show     .candor/report db.save 1   # a function's effects (match ladder)node query.mjs where    .candor/report Net 1       # direct sources vs inheritorsnode query.mjs callers  .candor/report db.save 1   # the blast radius (transitive callers)node query.mjs map      .candor/report 1           # module → effects overviewnode query.mjs containment .candor/report          # §6.1 boundary-effect dispersion (+ baseline = ratchet)node query.mjs blindspots  .candor/report          # the Unknown SOURCES, ranked by blast radiusnode query.mjs whatif   .candor/report db.save Net policy  # pre-edit gate verdict (exit 1)node query.mjs diff     .candor/report baseline 1  # per-function effect delta (exit 1 on a gain;                                                   #   a baseline from a DIFFERENT build ⇒ disclosed ⚠ + exit 0)node query.mjs gate --report dep/.candor/report.json --policy arch.policy --gate-json -                                                   # ⟨0.24⟩ apply a policy to an EXISTING report, NO scan                                                   #   (exit 0/1/2) — the supply-chain verb: gate a                                                   #   DEPENDENCY's published report without its source.                                                   #   Reads that report and nothing else; a rule the wire                                                   #   cannot answer (`forbid`, `allow`, a class-scoped                                                   #   `deny` with the scoping field absent) is REFUSED                                                   #   with exit 2, never evaluated on partial evidence.

A checked-in .candor/config (spec §3.4) replaces the env wiring — policy arch.policy / baseline <report.json> / deps <report paths> one per line, discovered by walking up from the scan target; relative values resolve against the config's repo, so CI is "point at the repo". A configured-but-unusable config/policy/baseline fails loud (exit 2), never silently gateless.

The scan-time baseline guard (AS-EFF-005, spec §7) makes effect regressions un-shippable: point CANDOR_BASELINE (or the config's baseline key) at a saved report, and any function that gained an effect fails the scan — exit 1, the records join the --gate-json verdict, each carrying origin (existing / new / unknown). ⟨0.40⟩ A function ABSENT from the baseline is compared against nothing, so a new effectful function fails too; a new pure one passes, and a new Unknown-only one is named in a note. Module.fn keys mean a renamed file reads as absent: review with candor diff <this run's report> <baseline> before re-recording. The guard is fail-closed like the policy gate: a present-but-unparseable baseline, or one produced by a different engine build (§2.1 — an engine upgrade is baseline-invalidating), exits 2 without evaluating; only a genuinely absent file is a one-line note (guard not active). Keep the two surfaces straight: query diff is the read-only comparison — it discloses a producing-build mismatch (⚠, exit 0) and informs; the scan-time guard is the gate-grade fail-closed surface, the one CI should hold. Semantics mirror the reference engine (candor-java) exactly.

Staying current: check your installed version and upgrade — candor/AGENTS.md §2a. npx -y candor-ts --version prints the build, the spec, and the upgrade one-liner (offline; candor never phones home).

Function names are module-qualified with . segments (src.db.save), so policy scopes read naturally. A function declared inside a TS namespace carries the namespace segments in fn and the callgraph keys (src.util.Ns.helper) — so layer policies on namespaces bite — while the §2 hash join key keeps the bare local name; builds before 0.8.7 omitted the segments, so crossing that line invalidates saved baselines (regenerate them). A pure <scope> rule forbids every effect but not Unknown — the §4 trust marker is uncertainty, not an effect (matching the reference engine, candor-java); deny Unknown <scope> is the explicit knob for boundaries that must also exclude the unverifiable case.

text
# .candor/policydeny Net domain                       # the domain layer reaches no network, even through helperspure  parse                           # parsing is effect-freeallow Db in db  orders audit_log      # the db layer touches ONLY these tablesallow Net in billing api.stripe.com   # billing talks ONLY to Stripeforbid domain -> infra                # the domain layer must not depend on infra

The report carries the four literal surfaces where a declaration makes them decidable — hosts at Net calls, tables at Db calls (SQL table positions, mirroring the Rust/JVM extractors exactly, plus TypeORM's @Entity("user") declarations read through the receiver's Repository<T> type argument), cmds at Exec, path-shaped paths at Fs — never from a runtime-computed value, propagated transitively, enforced by the allow rules above. On a real Nest app this makes table-level policy live: allow Db in article.service article comments flags the service reaching user and follows.

The classifier is curated (the same under-report-and-say-so posture as the other engines): the Node builtins (fs, net/http/tls, dns, child_process, worker_threads, node:sqlite, node:vm, process.env, the clock), the web network globals (fetch, XMLHttpRequest, navigator.sendBeacon, and WebSocket/EventSource — construction, send and close, charged identically whether they resolve through lib.dom or through @types/node's undici-types re-export), the HTTP/queue/mail tier (axios/got/node-fetch/undici/ws/ socket.io/nodemailer, gaxios + googleapis-common + google-auth-library, stripe, @sentry/*, posthog-node, bull/bullmq), the database drivers (pg/mysql2/mongodb/redis/ioredis/sqlite3/ better-sqlite3/knex) and the ORM tier (TypeORM — with @Entity("…") table extraction — Prisma, Mongoose, Sequelize, drizzle-orm), plus execa/cross-spawn/shelljs/open, fs-extra/ graceful-fs/rimraf/glob/chokidar, dotenv, winston/pino/bunyan. An unlisted npm package contributes nothing — candor never guesses an effect — but the scan names it: the receipt's coverage-ledger line (marker: classifier doesn't cover) lists every package the code demonstrably calls that candor's classifier neither classifies nor has reviewed-pure, and each function carries the invisible list it (transitively) reaches.

⟨0.32⟩ Node core is the one part of the classifier that is a denylist, not a curated list. The builtins are a finite set, so every module's surface is reviewed and a core member that is neither classified nor reviewed effect-free reads Unknown[native:<module>.<member>] — never pure. That is why v8.writeHeapSnapshot() is Fs, inspector.open() is Net, and repl.start(), process.dlopen() and new worker_threads.Worker(file) are visible holes rather than silence.

MCP server — candor as agent ground truth

candor-ts-mcp exposes the read-only queries as an MCP server, so a coding agent can ask "if I change this, what's the runtime blast radius?" or "what reaches the network?" and get deterministic ground truth from a precomputed report — instead of burning tokens tracing the call graph by hand (the measured ~700–2000× token win on blast-radius questions).

jsonc
// in an MCP client config — point it at a report you've already scanned{ "command": "npx", "args": ["-y", "candor-ts-mcp"],  "env": { "CANDOR_REPORT": ".candor/report.myPkg.scan" } }

Tools: candor_impact (backward blast radius), candor_reachable (what runs at runtime), candor_where (effect surface), candor_path (how an effect is reached), candor_callers, candor_show, candor_map, candor_containment, candor_blindspots, candor_whatif (pre-edit gate check — a given-but-unreadable policy is a loud error, never a clean verdict), candor_gate (the checked-in .candor/config policy verdict), candor_accepts (the §6.2 ⟨0.41⟩ proposal that refreshes or adopts accept lines; writes no file, and adopt needs the operator's because), candor_diff/candor_gains (baseline deltas). Each takes an optional report prefix (else $CANDOR_REPORT); --root <dir> locks the server to one workspace. The server is query-only — it never scans (the analyzer self-boundary, spec §7.12: an agent or a hook produces the report; the server reads it, Fs only). The query logic is the shared query-core.mjs, the same answers the CLI gives.

candor-lsp renders the same report where the code is, for any LSP-native editor (helix, neovim; the JetBrains plugin bundles it): a CodeLens per effectful function (⚡ Db, Net · blast radius 12), hover provenance (the hop chain to where an inherited effect is performed), and the repo's policy verdict as diagnostics. Like the MCP server it is a pure report consumer — any engine's report — and never scans. (Both report-computed gates are advisory: the engine's own --gate-json run additionally fails masked/incomplete literal surfaces and is the authoritative CI form.)

It also answers the pre-edit question in place: inside a function, a code action per boundary effect the fn doesn't yet perform — candor: what if handler performed Net? — runs the same whatif as candor-ts-query whatif/candor_whatif (blast radius + the policy rule that WOULD fire) and shows the verdict as a message plus a transient diagnostic at the function (cleared on the file's next open/save; with no policy discovered it says so and reports the radius alone). Plain textDocument/codeAction + workspace/executeCommand (candor.whatif) — it works unmodified in helix, neovim, VS Code, and JetBrains via LSP4IJ.

The live loop — candor-ts-watch keeps the report fresh as the agent edits, so the answers are about the current code, not a stale snapshot:

sh
candor-ts-watch ./src --out .candor/report   # re-scans only when a tracked source actually changes

It tracks the project's sources by content hash and re-scans on a real change (a no-op save or an unrelated write does nothing), writing the same prefix the MCP server reads. So: agent edits → watcher refreshes the report → agent asks candor_impact and gets the post-edit answer. And it reports the edit-delta — not just that the report is fresh but what the edit did to the effect surface (re-scanned (1 changed: app.ts) — Δ f +Net), so the agent learns the consequence of its own change. v1 runs a full (sound) scan per change; the deeper perf optimisation — re-analysing only the changed file's subgraph instead of the whole project — is the staged next step (the content-hash gate is its first increment).

Trust contract (spec §4)

Anything candor-ts can't resolve is designed to read Unknown, never silently pure — known open gaps are listed in candor-spec's SOUNDNESS.md (e.g. R780, R803, R804): a function-valued parameter or field being called, an any-typed callee, resolution landing on a type rather than a body.

An uncurated dependency can opt out of Unknown/silent-pure by declaring its effects in its package.json — "candorEffects": ["Net"] (spec §5.1, the effect manifest). candor-ts reads it as the declared-not-verified tier: the package's calls classify to the declared set, and it stops being a coverage-ledger blind spot. A name outside the §1 vocabulary voids the declaration loudly (a typo must not silently narrow a surface). And candor-ts-query gains <cur> <base> flags the supply-chain delta — the effects a surface gained between two reports. Real-world consequence, measured on rimraf (50 files, 55 functions analyzed): its DI-style fs injection means many functions read Unknown, disclosed — that's the contract working, not noise. The report says "can reach", never "does"; an absent literal is never a claim of absence.

Framework dependency injection (spec §2's bounded-CHA clause). rimraf's injection is a function-valued parameter, which reads Unknown. A DI container is measured separately, on NestJS 10 with an executed fixture:

  • a provider entry { provide: Store, useClass | useValue | useFactory | useExisting: … } whose token is a project CLASS is read as a conversion: the substitute joins Store's candidates, so this.store.save() is charged the union of Store.save and the substitute's save (SOUNDNESS R1061 — silent before, all three forms executed);

  • a parameter typed by an INTERFACE (@Inject("SINK") sink: Sink) dispatches over the project's visible implementors of Sink, so a useClass that implements Sink is charged; a useValue object literal that implements nothing reads Unknown (dispatch:).

  • the TOKEN is read through the checker's type, so const TOK = Store, an imported token, TOKENS.store and a .map over [Store] name Store; a helper's token/impl parameter is read through its visible call sites; a token typed Function/Type<any> joins its substitute to every project class it is assignable to (R1061);

  • a substitute the scan cannot name (useClass: impls[i] typed Type<Store>, a useValue typed any) makes a dispatch on the token class read Unknown (dispatch:).

Named miss: a provider list the scan cannot see at all (one imported from an unscanned package) and a substitute supplied by a dependency for a token the dependency owns. Gate a DI-heavy service with deny <E> Unknown as well as deny <E>.

Cross-engine consistency — machine-checked

candor-ts is one of the four code engines (with the reference engine candor-java, the Rust engines, and candor-swift) held together by the spec's cross-engine conformance suite: the shared effect-set oracle, the §6.2 policy-grammar battery (including allow Db), the §3.1 query-shape and match-ladder checks, the gate exit-code contracts, and the newer parts up through the pure-vs-Unknown ruling (PART 16) — the engines must answer identically, on every push to the spec.

What the analysis core implements (and where the spec told it how)

PieceSpec source
Resolve every call via the compiler API (getResolvedSignature), never syntaxCLASSIFIER §1
The classifier maps the resolved target's module (node:fs→Fs, node:net→Net, …)CLASSIFIER §2, TS notes
process.env property read → Env; Date.now → ClockSPEC §1
Local edges (cross-file) + least-fixpoint propagationSEMANTICS §5a
Closure bodies attribute to the nearest enclosing functionSEMANTICS §2
A call resolving to a type (function-typed field/param) → Unknown, never silent-pureSPEC §4
Unmatched external calls contribute nothing (curated-classifier caveat)SEMANTICS §8 C1
The literal surfaces hosts/cmds/paths/tables, literal-read onlySPEC §2
{ candor: { version, toolchain, spec: "0.41" }, functions } envelope; pure fns omittedSPEC §2/§2.1
Call-graph sidecar with every analyzed function a keySPEC §2.2
The gate: AS-EFF-006 / 008 / 009, loud on an unreadable policySPEC §6.2

Origin: the derivability proof

This engine began as a deliberately minimal single-file slice written from the spec documents alone (SPEC.md, SEMANTICS.md, CLASSIFIER.md) — without consulting the Rust or JVM sources — to answer executably: is the spec enough to derive a new-language implementation? Yes — 20/20 on the shared oracle. That clean-room claim is frozen at commit a29b152; everything since (multi-file projects, the query surface, the gate, the literal surfaces) is spec-implemented but post-hoc, and its guarantee is the conformance differential above, not clean-room provenance. The one engine-fix the original derivation needed (a call landing on a function-type declaration read as pure until §4 was applied to it) remains the proof point: the fix was "do what §4 says", not "go read the Rust source".

Status

Speaking candor-spec 0.41 (the package version is in package.json): the analysis core, the gate (--policy / --gate-json / .candor/config), the full §3.1 query surface (including containment, blindspots, the --include-unknown dispatch frontier, and ⟨0.24⟩ gate --report — the gate applied to an EXISTING report, byte-equivalent to scan --policy's verdict), the MCP server, the LSP server, and the watch loop are real, behaviorally tested (npm test — the behavioral suite across six harnesses), soundness-fuzzed with verified teeth (node fuzz.mjs — spec §7.13: generated effect chains through every encoded call form, any silent-pure = red), and conformance-held against the Rust/JVM/Swift engines. The npm classifier tier is deliberately curated and keeps growing case-by-case. Entry points (Nest/Next populations), unknownWhy origins, reachable, cross-package inheritance (CANDOR_DEPS + the spec §2 hash, version-trusted per §2.1), and --allow-js are all in. On npm: npx -y candor-ts <dir>. Per-release detail (⚠ marks report/verdict-affecting changes): CHANGELOG.md.

Development

No build step — the engine runs on Node directly.

sh
npm installnpm test            # the full CI gate: lint + unit (node:test) + behavioural + MCP + watch + the                    # fabrication probe + the §7.13 soundness fuzzernpm run test:unit   # just the native unit tests — the query algebra + policy DSL + the scan-core                    # classifier/literal leaves (query-core / policy / scan-core)npm run lint        # eslint (the recommended ruleset; the CI lint gate)node scan.mjs <dir | file.ts | tsconfig.json> --out .candor/report   # scan a project

The pure cores are factored into importable modules — query-core.mjs (the §3.1 queries), policy.mjs (the §6.2 DSL + literal matchers), and scan-core.mjs (the classifier + the SQL/ command/host extractors) — so they're unit-tested directly; the TS-compiler-driven walk stays in scan.mjs.

Agents: install candor as an MCP server

candor-ts ships candor's read-only query surface as an MCP server, so an agent asks "what is the blast radius of changing this?" or "what reaches the network?" and gets a deterministic answer from a precomputed report instead of grepping for it.

bash
npx -y candor-ts --mcp        # the server, over stdiocandor mcp install            # or let the umbrella write/merge .mcp.json for you

Registration instructions come from the package you already installed — candor mcp --help prints the .mcp.json snippet and the claude mcp add line, and candor mcp install writes them. There is no remote file to fetch, tamper with, or auto-execute, and nothing here tells an agent to run anything it did not already choose to install.

Discovery is passive: the manifest is server.json, published to the official MCP Registry so clients and directories can find candor without being handed a script.

The registry verifies namespace ownership from the mcpName field in package.json — that is the npm mechanism. (A mcp-name: README marker is the crates.io convention and does nothing here; the first cut of this used it, and the registry refused the publish with missing required 'mcpName' field. The line below is kept only because it is how a human greps for the namespace.)

mcp-name: io.github.tombaldwin/candor

来源:README.md,提交 ca86f53

工具

17

candor_impact

Backward blast radius: every effectful function that transitively calls `fn`, and which runtime entry points are downstream. Answers 'if I change this, what surfaces at runtime?' — the cheapest possible alternative to tracing callers by hand.

输入参数fn必填report

candor_where

Which functions perform a given effect (e.g. Net, Db, Exec, Fs) — `directly` vs `inherited` via a callee. The effect-surface map.

输入参数effect必填report

candor_reachable

What the program/fleet actually DOES at runtime: effects unioned over the entry points, with how many roots reach each and via which.

输入参数report

candor_path

Forward provenance: the shortest call chain from `fn` to the nearest function that performs `effect` DIRECTLY — 'this reaches Net through WHAT?'.

输入参数fn必填effect必填report

candor_callers

Who calls `fn` — direct (one hop) and transitive callers over the effect-relevant call graph.

输入参数fn必填report

candor_show

A function's effects (inferred = transitive, direct = own body) plus its literal surfaces (hosts/cmds/paths/tables) when present.

输入参数fn必填report

candor_map

Per-module effect overview: each module's union of effects and function count. The architecture-at-a-glance.

输入参数report

candor_whatif

Hypothetically add `effect` to `fn` and report the blast radius; with `policy`, also the deny-rule violations it would cause. Pre-edit gate check. ALWAYS CHECK for the presence of `ok`, never just its value: over a report this route cannot fully evaluate, `ok` is ABSENT and `{incomplete:true, ...}` takes its place — `affected`/`violations` still ship (a partial answer beats a refusal; this tool is consulted BEFORE an edit), but neither `true` nor `false` is a claim the input licenses. The causes are the same ones `candor_gate`/`candor_unverified` disclose: `unanalyzed` (candor could not read a file of the target's own code), `outOfScope` (the peek found a denied effect outside the scan's reach), `unread` (a class the scan never opened — gated on this call's OWN `deny`/`pure` rules, since only those depend on code outside the scan's scope), and `unaskedRules` (a class something DID open, but under a narrower deny set than this policy's own).

输入参数fn必填effect必填policyreport

candor_fix

THE BOUNDARY FIX: when `fn` performs `effect` in a layer the policy forbids (a violation candor_whatif/candor_gate reports), compute the architectural REMEDY — not just 'the domain can't do Net', but WHERE the effect belongs and the refactor to put it there: the direct call site to hoist, the forbidden-layer functions that become pure and thread the value as a parameter, and the nearest allowed-layer caller to perform the effect ({ crossing, site, deniedSpan, hoistTo, policyAlternative }). The remedial inverse of candor_whatif. Call this INSTEAD OF guessing a fix (adding `allow` to the domain, moving the I/O one call up, threading a handle the wrong way). Advisory: it names the structure, you write the code; the gate re-scan verifies. Uses `policy` if given, else the repo's checked-in .candor/config policy (spec §3.4). ALWAYS CHECK `refused` BEFORE `crossing`: where the policy narrows on evidence this report does not carry, candor_gate REFUSES and no remedy is computed — the result is `{ fn, effect, refused:true, unevaluated:[{rule, why}] }` WITH NO `crossing` KEY, an absent key rather than `crossing:false`, because 'no boundary fix needed' is a claim and that is the one thing the tool cannot claim here (spec §3.2: an advisory verb may be LESS certain than the gate, never MORE). Re-scan so the report carries the narrowing evidence, or widen the rule; do not read the missing plan as an all-clear.

输入参数fn必填effect必填policyreport

candor_gate

The policy verdict over this report: { ok, violations:[{rule, fn, effects, detail}] } — 'would this repo pass its architecture gate?'. Uses `policy` if given, else the repo's checked-in .candor/config policy (spec §3.4). ALWAYS CHECK `ok`, never the length of `violations`: a rule whose narrowing evidence the report does not carry is NOT EVALUATED, and then the result is `{ ok:false, refused:true, reason, unevaluated:[{rule, why}] }` WITH NO `violations` KEY — an absent key, not an empty list, because the gate is making no claim there. `unevaluated` also rides a firing verdict (a certain violation dominates a refusal). `incomplete:true` means the gate CANNOT be green, and the key beside it says which of the four causes fired: `unanalyzed` (the report declares code candor could not analyze), `outOfScope` (the producer's peek NAMED a function outside the scan's scope performing an effect this policy denies), `unread` (a class the producing scan never OPENED — its effects are absent because nothing looked, not because there are none; re-scan those sources WITH this policy), or `unaskedRules` (a class the producing scan's peek DID read, but under a deny set that does not cover this one — re-scan under THE SAME policy this tool is applying, not merely under a policy). Computed from the report — the engine's own --gate-json run is the authoritative CI form: it additionally fails an allow rule whose literal surface is INCOMPLETE (a masked/invisible endpoint), which is not a report field, so a green here can still be red in CI.

输入参数policyreport

candor_accepts

SPEC §6.2 ⟨0.41⟩ `accepts`: PROPOSE a refreshed policy — stale `accept` lines deleted, over-wide ones narrowed, exceeded ones proposed in a comment — as `{ mode, text, removed, narrowed, proposals, unnamed, unjudged, ignored, after, written:false, notes }`. It is the engine's own `accepts` verb (run in-process through the same code as `candor-ts-query accepts --json`, so the proposal is the CLI's, not a second implementation) and it WRITES NO FILE: `text` is the proposed policy, for a human to diff and commit. With `adopt:true` it also proposes a new `accept` line for each violation no entry names, and then `because` is REQUIRED — the operator's reason, written on every line it creates. NEVER INVENT A REASON: the engine does not compose one and neither may you; if the operator has not given you a reason, ask them. The reason you pass is echoed back as `adoptedBecause` so the operator can see exactly what was written in their name. Uses `policy` if given, else the repo's checked-in .candor/config policy. A stale report yields the STALE header like every tool here (re-scan first: a proposal over old code would accept the wrong rows). An incomplete or refused gate yields a tool error and no proposal.

输入参数adoptpolicyreportbecause

candor_unverified

PROVABLE-PURITY check (INSTANT): a `pure`/`deny <E>` policy layer PASSES a function that has no such effect — but if that function is Unknown (candor couldn't resolve one of its calls), the pass is UNVERIFIED: the Unknown could hide the very effect the rule forbids. The classic case is a fn/closure-injected 'port' — the domain reads as Unknown, so `deny Net domain`/`pure domain` clear it though it may reach Net at runtime. Returns each such function + the `deny <E> Unknown <scope>` upgrade that makes the layer PROVABLY clean. Uses `policy` if given, else the repo's checked-in .candor/config policy. ALWAYS CHECK `ok`, never the length of `unverified`: over a report declaring code candor could NOT analyze, `ok` IS ABSENT and `{incomplete:true, unanalyzed}` takes its place — a function in an unanalyzed file is missing from the report entirely, so it cannot be enumerated as an unverified pass, and an empty array there is not an all-clear (spec §3.2). `incomplete:true` also rides the three SCOPE causes, on the same terms as candor_gate: `outOfScope` (the producer's peek named a function outside the scan's scope performing a denied effect), `unread` (a class the producing scan never OPENED — re-scan those sources WITH this policy), and `unaskedRules` (a class the producing scan's peek DID read, but under a deny set that does not cover this one — re-scan under THE SAME policy this tool is applying, not merely under a policy). `ok` is ABSENT for a further reason too, and the entries that come with it are the sharpest ones: where the policy narrows on evidence this report does not carry, candor_gate REFUSES — and this verb then NAMES each function the gate could not judge, as `{fn, rule, why}` where `why` is THE MISSING EVIDENCE and never a derived class, plus the gate's own `unevaluated:[{rule, why}]`. Those entries carry no `upgrade`: whether they pass at all is the open question, so there is nothing to upgrade yet — re-scan so the report carries the evidence, or widen the

输入参数policyreport

candor_containment

Per boundary effect (Db/Net/Exec/Fs/Ipc/Clipboard): how contained it is in one architectural layer — the dispersion diagnostic (spec §6.1). Not a score; per-effect facts.

输入参数report

candor_blindspots

The Unknown SOURCES — calls the engine genuinely could not resolve (reflection, wide dispatch, fn-pointers) — ranked by how many functions inherit Unknown through each. Turns a high-Unknown report into a short worklist.

输入参数report

candor_diff

The per-function effect delta versus a baseline report: gained (introduced vs inherited) and lost effects. 'What did this change do to the effect surface?'.

输入参数reportbaseline必填

candor_gains

The supply-chain alarm: effects the surface GAINED versus a baseline (package-level + per-function) — 'did this dependency bump add Net/Exec somewhere?'.

输入参数reportbaseline必填

candor_activity

What the edit-time gate caught: MEASURED activity from .candor/activity.jsonl (the Stop-hook / standalone review log) — edits checked, verdicts, violations by AS-EFF code, effects introduced, largest blast radius, deepest propagation (hops), plus the most recent records. Counted from the log, no model. A missing log is an empty result (the loop isn't wired here — not an error); corrupt lines are skipped.

输入参数loglimitsincesession

版本历史

21
  1. v0.41.3最新Nov 7, 2026
  2. v0.41.0Nov 4, 2026
  3. v0.40.18Oct 31, 2026
  4. v0.40.17Oct 26, 2026
  5. v0.40.16Oct 25, 2026
  6. v0.40.15Oct 22, 2026
  7. v0.40.12Oct 16, 2026
  8. v0.40.10Oct 14, 2026
  9. v0.40.9Oct 13, 2026
  10. v0.40.8Oct 13, 2026
  11. v0.40.7Oct 12, 2026
  12. v0.40.6Oct 11, 2026
  13. v0.40.5Oct 11, 2026
  14. v0.40.4Oct 10, 2026
  15. v0.40.2Oct 9, 2026
  16. v0.40.1Oct 9, 2026
  17. v0.40.0Oct 8, 2026
  18. v0.39.1Sep 21, 2026
  19. v0.39.0Sep 20, 2026
  20. v0.38.3Sep 16, 2026
  21. v0.38.0Sep 16, 2026

评分

已满足适用检查项的 90%

该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。

  • 近 30 天内可连通25 分
  • 已声明认证方式10 分

    请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。

  • 已列出工具必需15 分
  • 描述必需15 分
  • 图标10 分
  • 文档15 分
  • 许可证10 分

其他 Candor 集成