sandstream-kit
v6.9.0
Published
developer kit. zero LLM, local-first, multi-vault. one command from git clone to working dev environment.
Readme
kit
One command from
git cloneto fully working dev environment.
For AI agents and humans. Manages tools, auth, secrets, and project setup. Zero LLM calls, local-first, multi-vault.
Your standards, not ours. kit ships zero opinions about your code or architecture — no bundled ruleset, no vendor's "best practice". You declare the standard (.kit.toml thresholds, your own plugin rules, architecture decisions as ADRs with enforce blocks); kit enforces the declaration deterministically and proves the checks ran. Taste may change: supersede the ADR, history keeps the why — and kit baseline freeze keeps day one honest by gating only net-new findings.
kit makes two promises concrete and keeps them across every major since 2.0: green = honest is externally provable (kit can emit a signed receipt, anchored to a key its own process cannot recompute, proving which scanners actually ran and that none failed open, verifiable offline), and kit's CLI, config schema, and plugin SDK are frozen, versioned contracts that do not break across a major line. kit 5.0 turns the provable local floor into a continuous, portable, fail-closed governance layer for the agent loop — hardware-rooted identity, an offline-verified control plane, one exec-broker enforcing a signed scope, and a traveling profile you can carry to a fresh host. See What's new in 5.0 and Stability & contracts.
Quick start
Prerequisites: Node.js 22+, git, and mise for installing tools (brew install mise, or curl https://mise.run | sh).
Platform support: macOS, Linux, and Windows via WSL2 or Git Bash. Native Windows (PowerShell/cmd) is not supported yet — kit's git hooks, tool resolution, and secret-file permissions assume a POSIX shell. On Windows, run kit from inside a WSL2 distro (recommended) or Git Bash. See docs/PLATFORM_SUPPORT.md.
# zero install (also sidesteps npm -g permission issues):
npx sandstream-kit setup
# or install globally:
npm i -g sandstream-kit
# if npm -g is permission-blocked, use a user-owned prefix instead of sudo:
# npm config set prefix ~/.npm-global
# echo 'export PATH="$HOME/.npm-global/bin:$PATH"' >> ~/.zshrc && source ~/.zshrcRun via Docker
Prefer a container (no local Node or mise)? The CLI ships as a signed image on Docker Hub. Mount your project and point the workdir at it:
docker run --rm sandstream/kit:latest --version
docker run --rm -v "$PWD":/work -w /work sandstream/kit:latest checkEach release publishes sandstream/kit (version + latest tags), keyless-signed
with cosign and shipped with a CycloneDX SBOM. Verify the signature before
trusting an image:
cosign verify sandstream/kit:latest \
--certificate-identity-regexp 'https://github.com/sandstream/kit/\.github/workflows/docker-build\.yml@.*' \
--certificate-oidc-issuer https://token.actions.githubusercontent.comThen, in a repo:
kit init # detect the stack → generate .kit.toml
kit check # what's set up vs missing (tools, services, secrets, hooks, deploy, security)
kit setup # install tools (via mise), git hooks, logins, secrets
kit context check # lock each CLI to the declared account + project (no wrong-org pushes)Fresh or ephemeral environment (cloud container, Claude Code on the web, CI, new
laptop)? Wire kit setup + kit memory sync into the environment's setup script
so it fuels itself — config, secrets (vault-backed), agent gates, identity, and
recall — with zero manual steps. See docs/ENV_FUELING.md.
What's new in 5.0
kit 5.0 takes kit from a point-in-time verifier to a continuous, portable, fail-closed governance layer for the agent loop. Four pillars, all additive over 4.x — no stable command removed. Highlights:
- Pillar 1 — hardware-rooted identity.
kit doctorsurfaces which backend signs kit's identity (Secure Enclave / TPM / external command vs. a file-backed 0600 key) and never silently downgrades;KIT_REQUIRE_HARDWARE_IDENTITYmakes a missing hardware backend fail-closed.kit identity migratemoves onto hardware and revokes the old key in one audited step. - Pillar 2 — control plane.
kit policy pull/pull-revocationsdistribute an org-signed policy, verified and enforced fully offline;kit policy approvemints offline signed approval tokens. Keyless egress signing is not shipped: the RFC 9421 HTTP Message Signature primitives exist and are tested (src/keyless/), and[scope].signis a real signed field thatkit doctorreports on (declared vs verified) — but nothing importssrc/keyless/outside itself, so no request on the egress path is ever signed. This entry previously described it in the present tense. - Pillar 3 — one exec-broker. A single signed-scope governance floor drives
the PreToolUse gates (
kit gate-egress/gate-fs), the MCP runtime, and thekit doctorposture. Runtime mediation is on by default in observe mode (audits what it would deny); enforce is an explicit opt-in. - Pillar 4 — traveling profile.
kit profiledeclares your{skills, mcp, workflows, plugins, vault, gates, scope}, audits declared-vs-discovered drift, signs the scope/RoE, and exports/imports a portable signed bundle to a fresh host — integrity-verified offline, fail-closed on tamper. - Deep skill triage.
kit triage skill --deepdelegates to NVIDIA SkillSpector's static Stage 1 (no LLM, no egress) andkit setup --recommendedwires the triage gates into your pre-commit hook. - Repo-map (
kit map/ MCPkit_map). A deterministic, zero-LLM code map: given a seed file, get the relevant slice of the repo — import neighbors (TS/JS + Python), a--budgetcap with a logged drop-list, owner attribution (CODEOWNERS or git-blame), and--co-changecoupling from git history — so an agent loads part of a growing repo, not the whole tree.
All of it holds the frozen CLI / config / plugin contracts. See CHANGELOG.md for the full list.
What's new in 3.0
kit 3.0 takes it from a provable local floor to an org-governed control plane — identity + policy is the contract. All additive over 2.x (no stable command removed; enforced by a public-surface invariant). Highlights:
- Identity + signable policy. A local Ed25519
kit identity, a signable, distributable.kit-policy.toml(policy-as-code) any kit verifies offline before enforcing, and a committed org trust anchor (.kit-policy.signers).kit panicrotates + emits a signed revocation. - Governed cross-device memory.
kit memory push/pullsync your private store over your own encrypted transport — a private git remote or anytransport = "command"(S3/rclone/scp/USB). Configurable without a backdoor: local-only config, remote ≠ project origin, AES-256-GCM payload, opt-in.kit memory sync initscaffolds it; opt-in auto pull-on-start / push-on-end makes ephemeral containers durable. PAL action items are device-coupled so a throwaway session never nags your laptop, andkit memory installwires the status-line so the "blocked-on-you" count is visible. - Tamper-evident, attributable audit. The HMAC anchor now binds attribution
(
kid/sig) into the seal — stripping or forging the signer of a sealed entry is caught (anchor v3). - Hardened gate. Closed install-gate bypasses (env-prefix,
npm exec/dlx, remote tarballs, subshells), two ReDoS, and a policy-canonicalization gap. - Smart, zero-LLM UX. Deterministic
💡 tip:hints surface the right capability at the right moment, andkit config knobslists the power-user env/config knobs.
See CHANGELOG.md for the full 3.0.0 entry.
Problem
Every time you (or an agent) starts on a new project:
- Missing CLI tools (supabase, vercel, eas, gcloud...)
- Not logged in to services
- Missing API keys and secrets
- Wrong versions
- No idea what's needed
Why kit exists
The same wall kept showing up, for a human at a new laptop and for an AI agent in a
fresh checkout: API keys scattered across .env files, shell history and password
managers (some live, some expired, none in one place); the same setup prompts burning
tokens to rediscover what the last session already knew; and an agent one npm install
away from pulling a package nobody vetted.
kit makes "get this project running, safely" declarative and repeatable: one config materializes tools, logins and secrets the same way every time, keeps credentials in a vault instead of on the loose, and puts a pre-install triage step in front of new dependencies so an unknown package gets looked at before it lands. Zero LLM calls, local-first, no telemetry, the intelligence stays where you put it.
kit is not another scanner
You already have Semgrep, Snyk, Trivy, Socket, your linters. kit does not compete with them. It runs them, folds in their results, and adds the layer they do not have.
- They go deep on one axis (code vulns, dependency CVEs, container images). kit
goes broad across the whole setup lifecycle: tools, auth, secrets and vaults,
git hooks, supply-chain triage, env routing, memory, governance. One command from
git cloneto a working, secret-safe environment. - kit orchestrates, it does not replace.
kit checkruns the local scanners it finds (Semgrep, Trivy, osv-scanner, GuardDog);kit scandrives the wider registry (snyk/trivy/grype/semgrep/osv/socket) and merges it into one verdict; thesnykandwizplugins ingest their findings; everything lands in one consolidated report next to kit's own checks, each with a remediation step. The cloud scanners (Snyk, Socket) run when their token is present and are dropped in air-gap mode —kit setupasks the network posture and points at where the tokens live (it never captures or stores them). - The one gate your agent runs. Before an AI agent acts it runs
kit reviewonce and gets a single deterministic verdict across every source. No agent, no socket, no telemetry, zero LLM calls. Your code never leaves the machine.
Use kit with your scanners. It is the connective tissue that turns them into one local-first, agent-native gate.
Security posture
kit is a security tool, so it holds itself to the bar it sets. The receipts:
- kit scans kit. Every push runs CodeQL, Semgrep, Trivy, gitleaks,
npm audit, OpenSSF Scorecard — andkit checkitself (dogfooding) in CI. - Signed, attestable releases. Docker images are keyless-signed with cosign and ship a CycloneDX SBOM; verify before trusting (see Run via Docker).
- Coordinated disclosure. Report a vulnerability via SECURITY.md — it carries the reporting path, a threat model + data-flow, an OWASP Top 10 assessment, and an incident-response plan with severity SLAs.
- Secrets never live in the repo. kit keeps credentials in a vault, materializes
.env.locallocally (gitignored), and scans code, staged diffs, git history and its own memory store for leaked keys. A stolen repo should contain no live secrets. - Supply chain is gated, not trusted.
kit triageruns before any install — fail-closed, "installs nothing untriaged" (aligns with OpenSSF S2C2F). - Green you can prove.
kit scan's verdict accounts for scanner health, not just findings, so a crashed, missing, or token-less scanner can no longer exit 0 silently (opt in to a hard fail withkit ci --strictor[governance.scan].required_scanners).kit check --attestwrites a signed receipt of which scanners actually ran plus the verdict, sealed with a machine-local anchor key; the.kit-audit.jsonlchain can be sealed withkit audit anchor. Honest scope: the anchor raises forgery from "anyone who can write the log" to "someone who can read the0600key", it is not tamper-proof against a same-UID local principal (that needs the documented external TSA anchor). - Local-first, zero LLM, no telemetry. Your code never leaves the machine.
At-rest note: kit's local memory store (
~/.kit/memory.db,0600) relies on OS full-disk encryption (FileVault / LUKS / BitLocker) today; application-level at-rest encryption is tracked as a follow-up.
Solution
.kit.toml per project:
[tools]
node = "22"
pnpm = "latest"
supabase = "2.78"
[services.supabase]
login = "supabase login"
check = "supabase projects list"
link = "supabase link --project-ref {project_ref}"
project_ref = "your-project-ref"
[services.vercel]
login = "vercel login"
check = "vercel whoami"
[services.stripe]
login = "stripe login"
check = "stripe config --list"
# auth strategy is inferred (interactive here, since a `login` command exists);
# override explicitly with: auth = "vault" | "capture" | "interactive"
# `kit login --plan` shows the resolved strategy per service before logging in.
[secrets]
store = "1password" # or env, dotenvx, vault, aws-sm, gcp-sm, azure-kv, infisical, doppler, bitwarden, eas
# Choosing a vault wires it up: kit adds its CLI to [tools] so `kit setup` installs
# it via mise (1password, infisical, doppler, bitwarden, vault), then guides login.
# Cloud secret managers (aws-sm, gcp-sm, azure-kv) are an exception — see below.
template = ".env.template"
[secrets.keys]
SUPABASE_URL = { source = "config", value = "https://{supabase.project_ref}.supabase.co" }
STRIPE_SECRET_KEY = { source = "1password", ref = "op://Development/Stripe/secret-key" }
REVENUECAT_KEY = { source = "eas", name = "REVENUECAT_APPLE_API_KEY" }
[setup]
install = "pnpm install"
migrate = "supabase db push"
seed = "pnpm seed"
verify = "pnpm dev & sleep 5 && curl localhost:3000"Commands
Complete reference: docs/COMMANDS.md. The shortlist:
kit init: Auto-detect project stack → generate.kit.tomlkit setup: Full pipeline: install → hooks → login → secrets → checkkit check: Status of tools, services, secrets, hooks, deploy env, security, testskit fix: Auto-remediate gaps (tools, gitignore, hooks, .env.template, declared deploy env) and print HITL blocks for auth / DSN setupkit review/kit heal: One-gate repo audit (check + design + standards + ADR); bounded self-heal loopkit adr {check,list,freeze}: Turn an Architecture Decision Record into a deterministic gate — enforce akit-enforceblock (forbid_pattern/require_pattern/forbid_import, incl. transitive and across npm package boundaries) cited back to the ADR. Zero-LLM (prose is never interpreted).kit/standards.d/*.toml: Declarative house-rule plugins supportmode = "forbid"andmode = "require"; directory excludes likescripts/meanscripts/**, with zero-match warningskit scan: Run external scanners (snyk/trivy/grype/semgrep/osv/socket) → one merged, air-gap-aware verdictkit supply-chain/kit sbom/kit gha-audit/kit agent-audit: Install-time triage, SBOM, Actions hardening, agent/MCP/hook auditkit self-audit: Deterministic self-check of kit's own source against the audit's bug-classes (also asserts CI-referenced scripts exist)kit coverage [--standard=<key>|all]: Evidence maps against 8 pinned standards — OWASP ASVS L2 · LLM Top 10 · Agentic Top 10 · MCP Top 10 · NIST SSDF 800-218A · NIST 800-53 Rev. 5 (control-family level) · AIUC-1 · GCP WAF Security — showing which controls kit's deterministic checks auto-verify vs gap/manual/n-a (evidence maps, not compliance attestations;--list-standardsto enumerate,--jsonfor GRC tools)kit sentinel {run,install,status}: Autonomous redline watcher (propose/apply guarded fixes)kit verify-provenance/kit ingest: Verify SLSA provenance offline; ingest external SARIF/OSVkit login --plan: Show the resolved auth strategy (vault/capture/interactive) per service without logging inkit secrets {set,migrate,rotate,propagate,onecli,validate}: Secret lifecyclekit memory {index,search,stats,suggest,merge,save,threads,share,backup}: Local-first, cross-harness second brain (per-harnessstats, project recall, saved copilots) +kit memory palpending-action ledger- Classified memory — partially wired, and this line says so rather than implying more. Every memory row carries a sensitivity class column, and the disclosure logic is implemented and unit-tested: recall filters to classes no more restrictive than the asking context, a missing or unrecognized class is excluded from every context (fail-closed), and an invalid configured value resolves to
restrictedrather than silently widening disclosure. What is not connected yet: no call site supplies the per-project class or the recall context, so every row currently takes the built-in default (internal) and the configured/environment override is inert. Until that wiring lands, do not rely on this to keep a note out of another project — see thedocumented env varscheck inkit self-audit, which is what caught it.
- Classified memory — partially wired, and this line says so rather than implying more. Every memory row carries a sensitivity class column, and the disclosure logic is implemented and unit-tested: recall filters to classes no more restrictive than the asking context, a missing or unrecognized class is excluded from every context (fail-closed), and an invalid configured value resolves to
kit auth {elevate,setup-totp,status,revoke}: Elevation gate + TOTPkit mcp {list,auth,set-token,clear}: MCP-server orchestratorkit env {list,switch,current,diff}: Environment routing + drift detectionkit context {check,use,--prompt}: Lock each CLI to its declared account + project (no wrong-org pushes)[agent_config.user_rules]: Per-repo opt-in to inject user-level prose from one file/directory into all managed agent rules files, capped by line/byte limitskit triage {npm,pip,docker,repo,skill}: Pre-install security checkkit security {scan-build,scan-staged,scan-artifact,verify-pull,costs,policy}: Security ops;scan-artifact <path>is the ingestion gate for an untrusted file/tree (ClamAV delegate — malicious or an unverifiable gap both fail).kit-secretsignore: Accept a reviewed secret finding by name (<commit>:<file>:<detector>, one per line). History is immutable, so a fixture committed once is a finding forever and the scan sits atwarnpermanently — a warning with no reachable green state is one nobody reads. Two properties keep it safe: an entry names one commit, so it can never wave through a future occurrence of the same string, and a verified-live finding is never ignorable regardless of what is listedkit hooks {install,add,sync}: Git hooks + bypass detectorkit governance/kit audit {secrets,verify,anchor,export}: Policy + audit-log inspection;anchor/verifyseal and check the external HMAC anchor[policy.agent_writes]: Declares which vendor writes are pre-approved — enforced since 6.3.2 at kit's own choke points (propagate(), secret rotation) and since 6.4.0 inside thekit-plugin-*packages, which receive the resolved decision as an exported deny list and never see your config. It only ever narrows: the block is unsigned config anyone who can edit the repo — including an agent — could add a line to, so declaring an op never satisfies elevation, read-only or signed approval (.kit-policy.toml+kit policy approveare the grant-shaped mechanism, and require an org signature). An empty list is a lock, not a wildcard; every grant and refusal is audited with vendor, op, state and policy hash. Seedocs/POLICY.mdkit check --attest(alsokit ci --attest/KIT_ATTEST=1): Opt-in signed receipt of which scanners ran + the verdict;kit check verify-attestation <file>verifies itkit check compare <before.json> <after.json>: Run-to-run diff of two--jsonruns — what actually changed since the last scan, which a baseline cannot tell you (freezing suppresses, it does not compare). Lost coverage outranks a regression:fail → skipmeans the check stopped running, so the finding is unknown, not fixed — a naive differ would call that an improvement.--fail-on-worsegates CI on the delta instead of the absolute verdictkit config migrate: Migrate a versioned.kit.tomlto the current schema (--dry-rundefault, auto-backup, re-validate-or-restore,--checkfor CI)kit airgap verify: Prove every scanner that would run in air-gap mode resolves to a local artifact (no egress)kit browser {doctor,status,cdp-url,playwright-env}: Which browser strategy a repo actually gets for verification — Playwright, system Chrome, or CDP — or the blocker in the way, plus the exports to wire a test runner (--jsonon each). kit owns local browser diagnostics, not app startkit --read-only <subcommand>: Session-wide refusal of all writes
What you'll see
kit init, detects the stack, previews .kit.toml, then runs setup:
kit init
──────────────────────────────────────────────────
✓ Detected: TypeScript / Next.js (confidence: 92%)
Preview, .kit.toml
+ [tools]
+ node = "22"
...
✓ Generated .kit.tomlkit setup, six-stage pipeline, each stage gated on the last:
kit setup
──────────────────────────────────────────────────
[1/6] Install
✓ node installed v22.22.2
[2/6] Git Hooks ✓ pre-commit installed
[3/6] Login ✓ supabase authenticated
[4/6] Secrets ✓ Wrote .env.local (from keys)
[5/6] Agent config ✓ Claude Code → CLAUDE.md (created)
[6/6] Verify
Setup complete, you're ready to go! ✓Step 5 teaches the agent in the repo (Claude Code, Codex, Cursor, Cline) to
use kit, it writes a small managed "run kit check / triage before install /
vault your secrets" block into the agent's rules file (CLAUDE.md, AGENTS.md,
.cursorrules, .clinerules). Run it standalone any time with kit agent-config.
The block is regenerated in place on re-run; edit outside its markers freely.
Agent support
kit is agent-agnostic — it's a CLI that any coding agent can run, plus opt-in adapters for the surfaces each agent exposes. Support today, per agent:
| Agent | Memory index¹ | "use kit" rules block² | Agent/MCP config audit³ | Perm allowlist⁴ | Auto-capture hooks⁵ | Blocking gate⁶ |
| :---------------- | :-----------: | :--------------------------: | :-------------------------------------: | :-------------: | :-----------------: | :------------: |
| Claude Code | ✅ | ✅ CLAUDE.md | ✅ + commands/agents/skills/plugins | ✅ | ✅ | ✅ hook |
| OpenAI Codex | ✅ | ✅ AGENTS.md | ✅ .codex/config | — | ✅ | ✅ hook |
| OpenCode | ✅ | ✅ AGENTS.md | ✅ opencode.json + .opencode/plugin | — | — | ✅ plugin |
| Cursor | ✅ | ✅ .cursorrules | ✅ .cursor/mcp.json | — | — | ✅ hook |
| Cline | ✅ | ✅ .clinerules | — | — | — | ✅ hook |
| Copilot | — | ✅ copilot-instructions.md | — | — | — | —⁸ |
| Gemini CLI | ✅ | ✅ GEMINI.md | — | — | — | ✅ hook |
| Continue | ✅ | — | — | — | — | n/a⁷ |
| Amazon Q | ✅ | — | — | — | — | ✅ hook |
| AWS Kiro | ✅ | ✅ AGENTS.md (shared) | — | — | — | ✅ hook |
| Factory Droid | ✅ | ✅ AGENTS.md (shared) | — | — | — | ✅ hook |
| Aider | ✅ | — | — | — | — | — |
| Antigravity | ✅ | — | — | — | — | ✅ hook |
| Augment | — | ✅ .augment-guidelines | — | — | — | ✅ hook |
✅ supported · — not yet · n/a not applicable (no surface) (#146)
kit memory indexparses the agent's local transcripts into the shared store.kit agent-configwrites the managed "run kit before installs / vault secrets" block into the agent's rules file.kit agent-auditflags plaintext secrets, cleartext/inline-code MCP servers, and malware-shaped hooks in the agent's config. Generic.mcp.json/.claude.jsonare scanned for every agent regardless.- kit can pre-authorize its read-only commands so they run without a prompt (Claude Code's
permissions.allowtoday). Codex has no equivalent command allowlist, sokit agent-configwrites a personalcodex --profile kitpreset (approval_policy = "on-request",sandbox_mode = "workspace-write") under$CODEX_HOME/~/.codexinstead of committing a repo risk preference. kit memory installregisters lifecycle hooks so capture happens automatically in Claude Code (~/.claude/settings.json) and Codex (~/.codex/hooks.json). Codex requires review/trust through/hooksbefore new command hooks run.- A true blocking gate (deny an un-triaged install before it runs) uses the agent's pre-tool hook —
kit agent-configwires it by default (--no-install-gateopts out) for Claude Code, Codex, Amazon Q, Gemini CLI, and Cursor (exit-2 hook commands); AWS Kiro, Factory Droid, Augment, and Antigravity via their hook/settings files (.kiro/agents,.factory/hooks.json,.augment/settings.json,.agents/hooks.json); OpenCode via a generated.opencode/pluginthat hookstool.execute.beforeand throws; and Cline via an executable.clinerules/hooks/PreToolUseshim that blocks through Cline's{cancel:true}stdout contract — 11 agents in all. The agent-agnostic enforcement floor is git hooks (kit hooks, pre-commit/pre-push) — they fire in any agent or none. See #146. - Continue exposes only a declarative tool-permission policy (
~/.continue/permissions.yamlallow/ask/exclude) with no way to invoke an external command before a tool runs, so a kit blocking-gate adapter isn't possible there — git hooks + the rules-file block remain its floor. - GitHub Copilot (VS Code / Visual Studio): the "use kit" rules block is written to
.github/copilot-instructions.md(wired when a.vscode/dir is present or the file already exists). Memory indexing and a blocking install-gate are not yet implemented — they need Copilot's transcript format and a pre-tool-hook surface verified against primary sources first. The git-hook floor + the MCP server (kit mcp, added to.vscode/mcp.json) apply today.
The git-hook layer enforces at the VCS boundary regardless of agent; the rules-file block is advisory (it reminds the agent); only the blocking-gate hook enforces before an action runs.
kit check, grouped status tables with a pass/fail summary:
Tools
✓ node 22.22.2 (need 22)
✗ supabase not installed (need 2.78)
Services
✓ vercel authenticated
Security
✓ .env gitignored pass all .env patterns in .gitignore
✓ pinned versions pass all dependencies pinned
7/8 checks passed (1 issues)
Run kit install to fix tools, kit login to fix authkit fix, six remediation steps, then a fixed/manual summary:
kit fix
──────────────────────────────────────────────────
[1/6] Tools ✓ supabase installed v2.78.0
[2/6] Lock Files ✓ Generated cli-lock.json
[5/6] .gitignore ✓ Added 2 pattern(s) to .gitignore
[6/6] Git Hooks ✓ Installed 1 hook(s): pre-commit
Summary
✓ Fixed 4 issue(s) automatically
! 1 issue(s) require human action:
HITL behövs
Blocker: stripe is not authenticated
Ägare: provider admin
Varför agenten inte kan lösa: auth / browser / external account
Gör detta:
1. Run `kit login --service stripe` in a normal terminal/browser session, or run `stripe login`.
2. Run `kit check --category services,secrets`.
Svara med: stripe configured/authenticated; no secret values pasted
Agenten fortsätter med: kit check --category services,secretskit secrets, resolves each key from the vault and writes .env.local:
Generating secrets... (env=dev)
✓ SUPABASE_URL resolved Derived from config
✓ STRIPE_SECRET_KEY resolved op://Development/Stripe/secret-key
✗ REVENUECAT_KEY missing not found in eas
✓ Wrote .env.local (from keys)kit triage <type> <target>, security verdict before you install:
Running triage on npm: left-pad
Health score: 7/10
Critical issues: 0
Warnings: 1
TRIAGE PASSEDTrust model documented in docs/THREAT_MODEL.md;
data flow per command in docs/DATA_FLOW.md;
release-verification in docs/VERIFY.md; how a release is cut, and
the migration off a long-lived npm token, in
docs/RELEASING.md. kit's verdicts are
produced by deterministic code, never an LLM — a CI-enforced contract, see
docs/ZERO_LLM_CONTRACT.md.
kit doctor: Deep diagnostics: Node.js version, mise, .env.local, tools in PATH, git hooks, and OS containment posture — detects the sandbox below the tool boundary (container / seccomp / user-ns, and gVisor / Firecracker fingerprints) and reports it honestly (unknownon non-Linux, never a false "not contained"). Set[governance.containment] require = trueto make it a fail-closed gate: doctor fails when containment can't be positively established (including when it can't be determined). kit detects/verifies a sandbox — it never becomes onekit env: Inspect environment variables from .env.local (--show-values,--missing,--json)kit mcp: Run the MCP server over stdio for AI assistants (auto-detected: no sub-command + non-TTY). Interactively,kit mcp list|auth|set-token|clearmanages declared serverskit analyze: Detect stack + emit draftCLAUDE.md/RULES.mdfrom git history + framework markers
Secrets management
End-to-end secret lifecycle, from .env* plaintext discovery, through vault
migration, to deploy-platform propagation, to destructive history cleanup.
kit secrets: Materialize.env.localfrom the configured vault storekit secrets set <KEY> --stdin | --value <v>: Capture a value straight into the vault (stdin-safe, never in argv). The execution behind a service'sauth = "capture"strategykit secrets migrate: Move plaintext credentials from.env*into the vaultkit secrets rotate <KEY>: Mint a new value (--randomopaque token /--value <new>explicit)kit secrets rotate <KEY> --from-cli: Provider-native playbooks (Stripe / AWS-IAM / GCP-IAM / GitHub PAT / OpenAI)kit secrets rotate <KEY> --via supabase-mgmt-api --project <ref>: Full automation via Supabase Mgmt API. Auto-detects scoped-key-mint vs jwt-secret-roll.kit secrets propagate <KEY> --to vercel,github,...: Push value to deploy targets (stdin-safe via--stdin)kit secrets revoke-old --via supabase-mgmt-api --key-id <id>: Revoke a previously-minted scoped keykit secrets onecli register <KEY> --host <pattern>: Register with the OneCLI gateway so the agent process never sees the real valuekit secrets purge-history <pattern> --force-history: Destructive: rewrite git history to scrub a leaked value (wrapsgit filter-repo/bfg). Requires elevation + explicit flag.
Deploy env matrix
Declare deploy-time key names in .kit.toml; commit names, never values. kit check --category deploy lists remote key names from the platform and diffs them against the declaration. With VERCEL_TOKEN, project is the active Vercel project name/id selector; without a token, kit falls back to the Vercel CLI and the target cwd link. NEXT_PUBLIC_* keys are treated as build-time: after setting one, redeploy before expecting the running frontend to see it.
[deploy.vercel]
scope = "example-team" # CLI fallback scope
team_id = "team_123" # API selector when VERCEL_TOKEN is present
environment_specific = ["NEXT_PUBLIC_SITE_URL"]
[deploy.vercel.environments.production]
project = "app-prod"
remote_env = "production"
required = ["NEXT_PUBLIC_SENTRY_DSN", "NEXT_PUBLIC_SENTRY_ENVIRONMENT"]
[deploy.vercel.environments.staging]
project = "app-stg"
remote_env = "production" # separate staging project; use "preview" for preview builds
required = ["NEXT_PUBLIC_SENTRY_DSN", "NEXT_PUBLIC_SENTRY_ENVIRONMENT"]Which vault CLIs kit installs. When you pick a secret backend at kit init, kit
provisions its CLI like any other tool — it adds the CLI to [tools], so kit setup
installs it via mise, resolves it mise-first at read time, and prints the login step.
This covers the dedicated vault CLIs:
| Backend | CLI installed by kit setup? | Authenticate with |
| ------------------- | ---------------------------------------- | ------------------------------------ |
| 1Password | yes (op via mise) | op signin |
| Infisical | yes (infisical via mise) | infisical login + infisical init |
| Doppler | yes (doppler via mise) | doppler login + doppler setup |
| Bitwarden | yes (bw via mise) | bw login + bw unlock |
| HashiCorp Vault | yes (vault via mise) | vault login |
| AWS Secrets Manager | no — uses your existing aws CLI | aws configure / IAM role |
| GCP Secret Manager | no — uses your existing gcloud CLI | gcloud auth login |
| Azure Key Vault | no — uses your existing az CLI | az login |
The three cloud secret managers are a deliberate exception: their CLIs are normally
already present (cloud installer, CI image, IAM environment), authenticate through
cloud-native mechanisms rather than a CLI login, and a second mise-managed copy could
shadow the system one. kit therefore guides their login but does not install the
CLI — it resolves the binary from your PATH and falls back cleanly if absent. Logging
in to any vault is always your own account action; kit never does it for you.
Security scanners
kit security scan-staged: Pre-commit: scan staged blobs for known credential patternskit security scan-build: Walk.next/,dist/,build/for credentials inlined into artifacts (NEXT_PUBLIC_typos)kit security scan-transcripts: Walk.claude/,~/.claude/projects/,.opencode/for replayed-secret leakskit security check-gitignore [--fix]: Verify.env*,*.pem,id_rsa,.kit/elevation.jsonare ignoredkit security verify-pull [--base <ref>]: Aftergit pull: audit new deps, gitignore drops, introduced secrets, policy changeskit security policy [init|add <pkg>|check]: Dependency allowlist enforcement + per-key spend caps/TTL/scopekit security costs: Snapshot per-key spend vs policy cap (Stripe live; OpenAI/Anthropic/Resend/Vercel stubbed)kit security clear-cache: Reset the cached supply-chain scanner binary (use after an intentional rebuild)
Self-audit
kit self-audit runs kit against its own source. It is zero-LLM and deterministic (walks src/*.ts, no network), so it can gate in CI. Two jobs in one: it scans for the same bug-classes the wider audit catches (reintroduced || true, unguarded dynamic imports, and the rest of the rule set), and it asserts that every script referenced from .github/workflows/*.{yml,yaml} (node/python files, npm run targets) actually exists, so a workflow can never point at a missing script.
kit self-audit: Run every enabled rule; print findings (text by default;--format=github/--format=gitlab/--format=jsonfor CI)kit self-audit --list-rules: Print the rule list (id, detection-class, severity) without runningkit self-audit --only <rule-id,...>: Run a subset of ruleskit self-audit --fail-on-warning: Treat warnings as failures (errors fail by default; warnings do not)
Error-severity findings (missing CI script, reintroduced || true, unguarded import) exit non-zero. It runs in kit's own CI (the self-audit job feeds the security gate), warn-only for the first rollout so only error-severity findings block.
Built-in git hooks
kit hooks add <name> installs a managed hook that calls back into kit. No .kit.toml config required.
secret-scan(pre-commit): Block commits that introduce known credential patternspost-pull-audit(post-merge): Runverify-pullafter everygit pull/ mergecontext-check(pre-push): Block a push when the live CLI context does not match.kit.toml [context](see Context lock)
Environments + elevation
Production credentials are gated behind explicit env-switching and short-lived elevation.
kit env switch <dev|staging|prod>: Toggle the active environment markerkit env current: Show active env (color-coded),kit env listfor availablekit auth elevate [--scope <op>] [--ttl-minutes N]: Mint a TTL'd elevation marker (TOTP or yes-prompt). Required before any destructive secret op.--list-scopes(also--json) prints every scope, what it unlocks, and whether it is one-shot — without elevating anything.kit auth setup-totp: One-time TOTP enrollment (writes~/.kit/totp-secret0600)kit auth status: Show active elevationkit auth revoke: Drop the elevation marker earlykit audit secrets [--since-days N] [--key <name>]: Forensics: who touched which key, whenkit audit verify [--strict]: Verify the keyless hash chain + the external HMAC anchor (a tip mismatch is a keyless prefix rewrite, a count mismatch is truncation/rollback).--strict(or[governance.audit].require_anchor, or once the machine has anchored any log) turns an unanchored log / unreadable key / unsealed tail into a hard failure, so a project-writablelog_filecannot repoint verification at a forged, never-anchored file and passkit audit anchor: Seal the current log with the machine-local anchor key (~/.kit/audit-anchor.key,0600) so a later keyless rewrite or truncation is detectable. The append path stays keyless (a sandboxed agent with no key keeps logging); the key is only needed to seal/verify. Key rotation reports as a distinctanchor-key-changedstatus, not a false tamper alarm. Honest scope: this is not tamper-proof against a same-UID principal who can read the keykit check --attest/kit ci --attest/KIT_ATTEST=1: opt-in, fail-soft (never blocks or alters the verdict). Writes.kit-check-attestation.jsonrecording which scanners actually ran plus the verdict, signed with the machine-local anchor key (authoritative; the verifier needs that key). An Ed25519 receipt is a portable fallback whose embedded public key is untrusted:kit check verify-attestation <file>reportsunverified-authenticity(not green) unless the key is pinned (TOFU in~/.kit, refuses silent overwrite) or passed via--key
Context lock
When you work across several accounts and projects (gcloud, Vercel, GitHub, npm) it is easy to be in the wrong one without noticing, and a logged-in account plus a selected project are not assumed to belong together. Declare the exact pair per repo and kit verifies the live tools against it:
[context]
gcloud = { account = "[email protected]", project = "acme-prod", config = "acme", region = "europe-west4" }
vercel = { team = "team_…", project = "prj_…" } # the ids in .vercel/project.json
github = { org = "acme", remote = "github.com/acme/app" }
git = { email = "[email protected]" }
npm = { registry = "https://registry.npmjs.org" }kit context check: verify the live account+project of each CLI matches the declaration. A right account with the wrong project is a mismatch, not a pass. Read-only; exits non-zero so it can gate.kit context use: activate the declared context (gcloud config + repo git identity). Touches only local config, never an account or a deploy.kit context --prompt: a fast, read-only indicator (e.g.[gcp:acme-prod]) for your shell prompt, so the context you are in is always visible.kit hooks add context-check: install a pre-push hook so a push to the wrong org/project is blocked before it leaves the machine.
Context pointers are non-secret and live in config; the credentials they authenticate with stay in the vault.
Quality gates (baseline-aware)
kit check --enforce-tests: Fail when net-new source files lack a sibling.test.tskit design: Static a11y scan (img-alt, button-empty, anchor-no-href, input-no-label) + design-token consistency (raw#hex/pxbypass).--enforceto gate,--jsonfor machine outputkit review: Meta-runner:check+design+standards+adrin one command. Use as a single PR-gate entry point for AI agentskit adr {check,list,freeze}: Enforce accepted ADRs' machine-readablekit-enforcerules over the repo, cited back to the ADR ("why is this blocked? → ADR-0007"). Rule types:forbid_pattern,require_pattern, and import-awareforbid_import(direct + transitive;follow_packages = truealso walks across npm package boundaries, catching "web must never reachpg, even through a wrapper dependency"). Anything the walk cannot follow to the end — an unresolvable import, an unreadable module, a depth/node bound — is surfaced as agap, never a silent pass. OnlyacceptedADRs gate; prose is never interpreted (zero-LLM).freezebaselines existing findings so only NEW ones failkit baseline freeze: Snapshot current findings (untested files, a11y, tokens, standards, ADR violations/gaps) into.kit-baseline.jsonso pre-existing warnings stay warnings and only net-new findings can failkit baseline show: Print current baseline
Supply chain
- Bumblebee: Built-in supply-chain scanner. Verifies every dependency against pinned SHA-256 checksums in
bumblebee.lock.json. Re-verifies the cache before reuse so a tampered local file is caught (kindintegrity). Runs in CI on every PR kit triage npm|pip|docker|repo|skill <target>: Pre-install security evaluation via triage skillkit triage npm <pkg> --sandbox: Offline behavioral inspection:npm pack→ extract → scan for install scripts, eval/base64/network patterns, unexpected scripts, oversized files. No code executeskit scan: Run the installed external scanners (Snyk, Trivy, Grype, Semgrep, osv-scanner, Socket) and merge them into one local, air-gap-aware verdict. GuardDog (opt-in viaKIT_GUARDDOG=1or[scan] guarddog) adds local malware detection. The cloud scanners (Snyk, Socket) run when their token is set (SNYK_TOKEN/SOCKET_SECURITY_API_TOKEN, resolved from[scan.tooling]vault or env — kit never stores them) and are dropped in air-gap mode;kit setupasks the network posture (connected vs enclave) and writes[air_gap]. Socket has no stable findings-JSON, so kit gates onsocket ci's exit code (never false-green). Token absent → the scanner is skipped, not failed- Scanner-health gate. The exit verdict accounts for scanner health, not just findings: a scanner that errored, isn't installed, or lacked its token can no longer exit 0 (a false green). Default is a loud warn (no existing green CI breaks); opt in to a hard fail via
[governance.scan].required_scanners(a listed scanner that didn't run fails) orkit ci --strict/KIT_CI_STRICT=1(any non-running scanner fails) kit airgap verify: assert every scanner that would run in air-gap mode resolves to a local artifact (no cloud-only scanner, no registry config) and print a pass/fail table. In air-gap mode a registry (p/…)KIT_SEMGREP_CONFIGis refused in both scan paths (it would egress to the semgrep registry), while a local ruleset path is kept so semgrep can still run fully offline- Supply-chain findings auto-append to
.kit-audit.jsonl(one JSON line per finding) for SIEM ingest - Releases ship with SLSA provenance (
npm publish --provenance), CycloneDX + SPDX SBOMs on every GitHub release, cosign-signed Docker images, and weekly OpenSSF Scorecard
Shell guard (observe mode)
The agent loop is gated (the PreToolUse install-gate across 11 harnesses), but a
human typing npm i x / npx y / brew install z in their own terminal reaches
the machine ungated. kit guard install writes PATH shims for the install +
fetch-and-run family (npm npx pnpm yarn bun bunx pip pip3 pipx uv uvx brew gem
cargo) that run the same hardened parser + triage verdict the agent gate
uses — and log what it WOULD decide to ~/.kit/guard-observe.jsonl.
v1 is observe-only by the exec-broker discipline (observe → evidence →
enforce): a shim never blocks and never breaks the tool — kit missing or
crashing means unchanged behavior, non-install subcommands pass silently, and
KIT_GUARD_BYPASS=1 skips observation for one call. kit guard status shows
what has passed through and what enforce mode would have stopped; kit guard
uninstall removes everything. Notable: the shims also see the npx-spawned
MCP servers agent harnesses launch outside any Bash gate — coverage the
PreToolUse hook can't reach.
A shim hands the call to the next match on PATH, so another shim manager
(mise, asdf, pyenv, rbenv) still chooses which version runs — but kit drops its
own directory from PATH before handing off into one, because those managers
re-resolve the tool through PATH and would otherwise land back in kit's shim
forever (#461). Shims also
self-heal: kit guard-observe rewrites the shim that called it when the file
predates the running kit version, so an upgrade doesn't leave old wrappers
behind, and kit guard status names any that are still stale.
Compliance evidence
kit coverage emits deterministic evidence maps: it maps kit's own checks and self-audit rules to a vendored, pinned, curated subset of a standard's controls and buckets each as auto-verified, gap, manual, or n-a. --json (or --format=json) emits the structured report for a GRC tool to consume.
Eight standards are registered (--list-standards; --standard=<key>, or all): OWASP ASVS 4.0.3 L2 (default) · LLM Top 10 · Agentic Top 10 · MCP Top 10 · NIST SSDF 800-218A · NIST 800-53 Rev. 5 · AIUC-1 · GCP WAF Security. Toggle the set with [coverage].standards in .kit.toml (absent ⇒ all on).
The NIST 800-53 map is deliberately at the control-family level (20 families, not ~1000 controls): a family bucketed auto means kit emits deterministic evidence relevant to it — never that every control in it is satisfied. Physical, personnel, and organizational families (PE/PS/AT/CP/MA/MP) are n-a by charter rather than quietly claimed.
It is explicitly an evidence map, not a compliance attestation: it never claims "compliant". The goal is to be the deterministic evidence source a GRC tool ingests, not a worse version of one. (experimental tier.)
Stability & contracts
As of 2.0, kit's public surfaces are versioned contracts, not just code that happens to work today.
- Command stability tiers. Every command carries a
stable | experimental | deprecatedtier.stablecommands will not be removed, renamed, or have their exit-code /--jsonsemantics broken across 2.x (additive-only in minor releases). All shipped commands arestableexceptteam(experimental);deprecatedcommands print a stderr warning every run. A committedcontracts/public-surface.jsongolden snapshot plus a drift test enforce this: a surface change fails CI until it is reviewed, regenerated, and labeledBREAKING. See docs/CLI_STABILITY.md. - Versioned
.kit.toml. The config carries a top-levelversion(CONFIG_SCHEMA_VERSION = 1; an absent field is treated as legacy v0).kit config migrateruns an ordered, fixture-tested migration from the detected version to the current one:--dry-run(the default, which prints the plan and a value-level diff and writes nothing), a real run writes.kit.toml.backupfirst (refuses to clobber an existing backup without--force) then re-parses and validates the result and restores the original on any failure, and--checkexits non-zero on a stale config for CI. Upgrade note: runkit config migrateonce; v1 is the baseline (a no-op version stamp), so nothing breaks today, but the migration path is now in place for any future schema change. [email protected]is frozen on its own semver track, decoupled from kit's version, with a documented public surface, a kit-compatibility matrix, and caret-pin guidance (see docs/API_STABILITY_AND_VERSIONING.md).
Memory
kit memory gives an agent a local-first, deterministic second brain, it stores
your raw conversation history and searches it before answering, so it pulls
receipts instead of guessing. SQLite + FTS5, three lifecycle events per supported
hook harness, no vectors, no model calls.
It indexes transcripts from twelve coding agents (Claude Code, Codex, Gemini,
Continue, Cursor, Amazon Q, AWS Kiro, Factory Droid, Aider, Antigravity, Cline, and
OpenCode), each parsed against the agent's own serialization format, never guessed. A private personal tier (encrypted backup so a
stolen laptop doesn't lose your context, plus opt-in cross-device sync — your
own git remote or command, ciphertext-only, with a public-key mode so even a
throwaway cloud session can contribute with no secret) plus a curated,
area-organized shared tier that travels with the repo and is reviewed like code.
kit memory install && kit memory index
kit memory search "what did we decide about X" # project-scoped recall
kit memory area stripe # shared: how we built it, status, security
kit memory suggest | your-llm # zero-LLM core; pipe a review prompt to YOUR modelFull reference: docs/MEMORY.md. Original schema + hook design
credited to cloudctx (MIT).
Lock Files
kit uses lock files in .kit/ to track exact versions of skills and tools:
.kit/kit.json: Identifies which kit this project uses (e.g., "sandstream/[email protected]").kit/skills-lock.json: Agent skills with versions and metadata.kit/cli-lock.json: CLI tools with versions and installation sources
This allows teams to codify and version their development methodology, similar to package-lock.json for dependencies.
kit init # Generate lock files and setup project
kit upgrade # Update lock files from .kit.toml
kit check # Verify lock files are in syncService Provisioning
kit can automatically provision and configure services for your project, designed for agent-native workflows (no browser required):
kit add stripe/payments # Set up Stripe with API keys
kit add supabase/db # Initialize Supabase project
kit add vercel/hosting # Link repository to VercelHow it works
- Checks if the service CLI is installed and authenticated
- Provisions resources via CLI/API (no browser needed)
- Extracts credentials and configuration
- Writes secrets to
.env.local - Records provisioning metadata in
skills-lock.json
Available Services
stripe/payments: Payment processing with Stripe
- Requires:
stripeCLI (install) - Provisions: API keys, creates test mode configuration
- Secrets:
STRIPE_SECRET_KEY,STRIPE_PUBLISHABLE_KEY - Example:
brew install stripe/stripe-cli/stripe stripe login kit add stripe/payments
- Requires:
supabase/db: Database and authentication with Supabase
- Requires:
supabaseCLI (install) - Provisions: Local dev instance or links existing project
- Secrets:
SUPABASE_URL,SUPABASE_ANON_KEY,SUPABASE_SERVICE_ROLE_KEY - Example:
brew install supabase/tap/supabase supabase login kit add supabase/db
- Requires:
vercel/hosting: Hosting and deployment with Vercel
- Requires:
vercelCLI (install) - Provisions: Links repository, sets up deployment
- Secrets:
VERCEL_PROJECT_ID,VERCEL_ORG_ID - Example:
npm i -g vercel vercel login kit add vercel/hosting
- Requires:
expo/eas: Mobile app builds with Expo EAS
- Requires:
easCLI (install) - Provisions: EAS project, build configuration
- Secrets:
EXPO_TOKEN, EAS credentials - Example:
npm i -g eas-cli eas login kit add expo/eas
- Requires:
searxng/instance: Privacy-respecting search engine
- Requires:
dockeranddocker-compose - Provisions: Local SearXNG instance
- Secrets:
SEARXNG_URL,SEARXNG_SECRET - Example:
kit add searxng/instance
- Requires:
The full adapter set (each provisions/reuses the relevant keys; run kit add <id>):
| Service | Purpose |
| --------------------- | ----------------------------------------------------- |
| stripe/payments | Stripe payment processing (products + price IDs) |
| supabase/db | Supabase database + authentication |
| vercel/hosting | Vercel hosting + deployment |
| flyio/hosting | Fly.io container deployment |
| railway/hosting | Railway (Heroku-style) deployment |
| neon/db | Neon serverless Postgres |
| planetscale/db | PlanetScale serverless MySQL |
| upstash/redis | Upstash serverless Redis |
| cloudflare/r2 | Cloudflare R2 object storage (S3-compatible) |
| clerk/auth | Clerk authentication + user management |
| resend/email | Resend transactional email |
| loops/email | Loops marketing + transactional email |
| sentry/monitoring | Sentry error tracking + performance monitoring |
| posthog/analytics | PostHog product analytics + session recording |
| tinybird/analytics | Tinybird real-time analytics on ClickHouse |
| liveblocks/realtime | Liveblocks collaborative realtime (presence, cursors) |
| trigger/background | Trigger.dev background jobs |
| inngest/background | Inngest event-driven background jobs |
| flagsmith/flags | Flagsmith feature flags + remote config |
| expo/eas | Expo Application Services (mobile builds) |
| searxng/instance | Self-hosted SearXNG search engine |
Add your own with kit create-plugin <name> (see docs/PLUGIN_DEVELOPMENT.md).
Example Workflows
New project setup:
# Clone project
git clone https://github.com/user/my-app
cd my-app
# Check what's needed
kit check
# Provision all services at once
kit add stripe/payments
kit add supabase/db
kit add vercel/hosting
# Verify everything is configured
kit checkAgent-driven provisioning:
# Agent provisions services automatically
kit add stripe/payments
# → Checks if stripe CLI installed
# → Verifies authentication
# → Creates API keys
# → Writes to .env.local
# → Updates skills-lock.json
# Check what was provisioned
cat .env.local | grep STRIPE
cat skills-lock.json | jq '.provisioned["stripe/payments"]'Creating custom adapters:
See docs/CUSTOM_ADAPTERS.md for a complete guide on creating custom service adapters.
Troubleshooting:
Common issues and solutions:
- "Required tool not installed": Install the service's CLI tool (see examples above)
- "Not authenticated": Run the service's login command (e.g.,
stripe login) - "Provisioning failed": Check CLI is in your PATH:
which stripe - For more help, see docs/CUSTOM_ADAPTERS.md
Agent Integration
Agents run kit check at start. If anything fails:
- Auto-fix what's possible (
kit fix) - Escalate to human what requires browser auth (
kit escalate) - Continue working on what's available
Governance & Access Control
kit includes governance features for managing agent access to production systems:
[governance]
enabled = true
environment = "dev" # dev, staging, prod
[governance.access]
dev = { read = true, write = true, delete = true }
staging = { read = true, write = true, delete = false }
prod = { read = true, write = false, delete = false }
[governance.agent]
id = "agent-123"
name = "Founding Engineer"
max_tokens_per_day = 1000000
max_operations_per_hour = 100
[governance.audit]
enabled = true
log_file = ".kit-audit.jsonl"
[governance.approval]
destructive_operations = ["delete", "drop", "truncate"]
production_writes = true
[governance.revocation]
enabled = true
revocation_endpoint = "https://audit.example.com/agents/{agent_id}/status"Features
- Environment-based access control: Different permissions per environment
- Audit logging: All operations logged with automatic secret redaction
- Budget limits: Token (daily) and operation (hourly) tracking
- Approval gates: Interactive prompts for destructive operations
- Revocation: Remote status checking via API
- Secret expiration: Monitoring with warnings for expiring secrets
Environment Detection
kit automatically detects the current environment using:
- NODE_ENV environment variable (highest priority)
- Git branch name (fallback: main/master→prod, staging→staging, others→dev)
- Default to dev if neither is available
Set NODE_ENV in your .env.local:
# Options: development, staging, production
NODE_ENV=developmentThis affects governance access control, security policies, and audit logging.
See GOVERNANCE.md for detailed documentation.
AI Assistant Setup
The one-line agent bootstrap
The fastest adoption path needs no human setup at all: paste ONE line into the
repo's CLAUDE.md / AGENTS.md (or your global agent rules) and the next
agent session bootstraps kit itself — install, init, verify — and asks the
human only for what is genuinely theirs (interactive logins):
This project uses kit (github.com/sandstream/kit). If `kit` is missing: `npm i -g sandstream-kit`, then `kit init` (detects the stack, generates .kit.toml, wires agent config + install gates). Start every session with `kit check` and act on its verdict; `kit fix` auto-repairs; interactive steps like `kit login` belong to the human — suggest they run them (in Claude Code: prefix with `!` so the output lands in the session). `kit <command> --help` self-documents.What the agent does from that line: installs kit globally, runs kit init
(which also writes the managed "use kit" block into the rules file — the
one-liner retires itself), runs kit check, and walks the human through the
gaps. Trust note: this first install is your trust root — kit can't triage its
own bootstrap. Releases carry SLSA provenance and cosign-signed images; see
docs/VERIFY.md to verify before you paste the line into an
org-wide template.
Transparent end state — you should know exactly what a line you paste will turn into. When the bootstrap completes, your rules file contains this managed block and nothing else has been touched (visible BEGIN/END markers, idempotent — re-runs update only the region between them):
<!-- BEGIN kit (managed block — edit outside the markers, not inside) -->
## kit
This repo is managed by [kit](https://github.com/sandstream/kit) (env, secrets, security gates). Hooks enforce the hard rules; what you need to know:
- If `kit` is missing (fresh clone/machine): `npm i -g sandstream-kit`, then continue below.
- Start: `kit check` — on `fail`, run `kit fix`, then re-check.
- Prior decisions: `kit memory search "<query>"` (cross-session, cross-agent).
- Secrets: `kit secrets` (vault-backed); placeholders go in `.env.example`, never plaintext in `.env*`.
- Deploy env: `[deploy]` declares required platform key names; `kit check --category deploy` diffs remote names without reading values.
- Deps the install gate hasn't covered (git repos, URLs, vendored code): `kit triage repo <target>` first.
- After a batch of edits: `kit check --category security`; halt and surface findings on `fail`.
- Everything else: `kit --help` — the commands are self-documenting.
<!-- END kit -->The block is an index, not an encyclopedia — every agent turn pays for these
tokens, so anything a hook already enforces deterministically carries zero
prose here. A drift test pins this README example to the KIT_INSTRUCTION
the code actually writes, so the promise can't rot.
kit exposes its capabilities as an MCP server, making it usable directly by Claude Code, Cursor, Windsurf, Cline, and any other MCP-compatible AI assistant. Once registered, assistants can call kit_check, kit_fix, kit_triage, and other tools without leaving their context. (An agent with shell access should prefer the CLI — zero standing context cost, and kit <command> --help self-documents; the MCP surface exists for shell-less clients. The server's instructions field tells clients exactly this.)
Claude Code
A template config is included at claude-mcp.json. Copy it to activate:
cp claude-mcp.json .claude/mcp.jsonOr add manually to .claude/mcp.json (or ~/.claude/mcp.json for all projects):
{
"mcpServers": {
"kit": {
"command": "npx",
"args": ["sandstream-kit", "mcp"]
}
}
}Or if installed globally (npm install -g sandstream-kit):
{
"mcpServers": {
"kit": {
"command": "kit",
"args": ["mcp"]
}
}
}Cursor
.cursor/mcp.json is already included in this repo. For other projects, add to .cursor/mcp.json in your project root:
{
"mcpServers": {
"kit": {
"command": "npx",
"args": ["sandstream-kit", "mcp"]
}
}
}Windsurf / Cline
In Windsurf, open Settings → MCP Servers and add:
{
"kit": {
"command": "npx",
"args": ["sandstream-kit", "mcp"],
"transport": "stdio"
}
}For Cline, add the same config to your cline_mcp_settings.json.
Available MCP Tools
| Tool | Description |
| --------------- | ----------------------------------------------------------------------------------------------- |
| kit_check | Run all checks, return structured status JSON |
| kit_review | Full repo audit — check + design + standards + ADR gates as one structured report |
| kit_fix | Auto-fix issues (install tools, generate lock files) |
| kit_triage | Security-triage a dependency BEFORE installing it — a pass satisfies the install gate |
| kit_memory | Search cross-session memory + the repo's curated shared decisions (search-only) |
| kit_secrets | Generate .env.local from configured sources (r
