neuron-explorer
Qwen3.5‑4B 전용 조향형 뉴런 탐색기, 모든 MLP 뉴런을 밀어 결과를 보관·탐색
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Sponson turns a release's side effects into a file an agent can read and a human can diff.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Sponson is the plan for everything that ships beside the code.
A sponson is the float welded to the side of a hull so the boat does not roll. The code is the hull. The preview database, environment variables, callbacks, and feature flags are the float. Sponson writes that float into one file an agent can read and a human can diff.
Agents can already change a repository. They cannot safely change the rest of a release.README 전문 보기 ↗Sponson is Terraform-style plan/apply for per-PR preview state (database branches, env vars, auth callbacks) in one YAML file, with drift detection and teardown.
A sponson is the float welded to the side of a hull so the boat does not roll. The code is the hull. The preview database, environment variables, callbacks, and feature flags are the float. Sponson writes that float into one file an agent can read and a human can diff.
# release.plan.yaml
version: 1
providers:
vercel: { project: prj_xxx }
neon: { project: proj_xxx }
changes:
- id: db
adapter: neon
op: branch
environments: [preview]
- id: env
adapter: vercel
op: env
target: preview
values:
DATABASE_URL: { from: db.connection_string } # a reference, never a value
STRIPE_KEY: { secret: "env://STRIPE_KEY" } # a reference, never a value
environments: [preview]
- id: callback
adapter: clerk
op: redirect_allow
url: { from: env.preview_url } # exists only after the deploy
environments: [preview]
$ sponson plan
sponson plan · preview · pr-42 · plan 0583f85b
+ db neon.branch create Neon branch sponson/preview/pr-42
? env vercel.env pending waiting on `db`
+ DATABASE_URL (preview, feat/checkout) (pending ← db.connection_string)
+ STRIPE_KEY (preview, feat/checkout) (secret ← env://STRIPE_KEY)
? callback clerk.redirect_allow pending waiting on `env` (deploy)
+ Clerk redirect (pending ← env.preview_url)
1 to create, 2 pending
The first apply creates the branch and writes both variables, then stops at the deploy barrier: the callback needs
the preview URL, which exists once the deploy finishes. The next apply (the one the deploy triggers in CI) finishes
it.
$ sponson apply
sponson apply · preview · pr-42 · run run-1a2b3c4d
+ db neon.branch applied Neon branch sponson/preview/pr-42
+ env vercel.env applied DATABASE_URL (preview, feat/checkout), STRIPE_KEY (preview, feat/checkout)
? callback clerk.redirect_allow waiting waiting on deploy
outputs
db.branch_id = br-11
db.host = br-11.sim.neon.tech
apply partial: callback waits for the deploy
Both are real output: pnpm docs:gen runs this plan against the fake cloud below and writes what the CLI prints here.
No Vercel, Neon or Clerk account needed: @sponson/sim is a local fake cloud with their APIs. You need Node.js 22
or later, git and curl. In one terminal, start it with a ready demo repository:
npx --yes @sponson/sim --demo sponson-demo
Leave it running. In a second terminal, run these one at a time (the first terminal prints the same list):
cd sponson-demo && source sim.env
sponson plan
sponson apply
sponson apply
curl -s -o /dev/null "$SPONSON_SIM_URL/_chaos" -d '{"drift":{"vercel.env.preview.DATABASE_URL":"postgres://typed-in-the-console"}}'
sponson plan
sponson apply --destroy
sim.env points sponson at the fake cloud with placeholder tokens, and makes sponson the published CLI of the
sim's own version, through npx (a shell function, so a global install of another version cannot get in the way).plan reads live state and prints the diff of release.plan.yaml: a Neon branch to create, and a DATABASE_URL
and a Clerk redirect that wait on it. Nothing is written.apply creates the branch, writes its connection string into Vercel's DATABASE_URL by reference (the password
is never printed), finds the preview deployment of this commit, and allows its URL as a Clerk redirect.apply again: every line unchanged, zero writes.curl plays someone editing DATABASE_URL in the Vercel console.plan reports the drift and blocks that line (x, exit 1): apply will not overwrite it without --reconcile.apply --destroy removes everything the demo created, in reverse order, and warns that DATABASE_URL was
changed outside Sponson before it deleted it. Ctrl-C in the first terminal stops the fake cloud.scenarios/docs/try-it.test.ts runs these exact commands from this file on every CI run.
Agents can already change a repository. They cannot safely change the rest of a release.
The code lands in Git. The things that have to move with it do not. A preview database lives in the database console. Environment variables live in the deploy console. OAuth callbacks live in an identity console. Feature flags live in a fourth. A person copies state between them by hand. An agent does the same thing with no shared record of what it intended, what it tried, and what a human approved.
Existing tools each own one slice. Terraform and Pulumi plan resources, not the preview data and callback that belong to this release. Vercel and Railway deploy the app, not the secrets and flags that have to match it. Doppler and Infisical hold secrets, not the release those secrets belong to. A sequence of agent tool calls is not itself a record. A release needs its own file.
Sponson is that file. The format is the product. A hosted approval inbox can come later. A new cloud does not.
One release, one plan. Three commands.
| Command | What it does | Writes anything? |
|---|---|---|
sponson init | Detects your stack from the repository's files (every supported provider, the framework and ORM) and writes a plan for it, with the project ids it can find and a # TODO: naming where to find each one it cannot. Run again to adopt resources the plan does not know about. | the plan file, and .sponson/ (local receipts) in .gitignore |
sponson plan | Reads live state, prints the diff and any drift. Exits 1 when a line is blocked (x): drift, a missing secret, or a refused line it depends on. | no |
sponson apply | Runs the plan in dependency order. Rolls back what this run created if a line fails. Writes a receipt. | yes |
{ secret: "env://NAME" }, or any other secret scheme. Every command resolves them, plan and apply --destroy included (so a scheme backed by a secret manager's CLI runs that CLI on plan too), and registers each value for masking before anything is printed; only apply hands values to an adapter. They are redacted from every byte of output. A literal that looks like a secret is rejected at parse time.{ from: db.connection_string } reads another line's output. Outputs that only exist after an external event (a deploy) stop the run with status partial; the next apply continues from there. Same command, no flags.plan says so; apply refuses that line until you pass --reconcile. Something exists that the plan does not mention? It is listed and left alone.sponson-receipts/<env>/<scope>, so unrelated pull requests never wait on each other): a ledger of every resource the scope owns (kept across failed, refused and crashed runs), what each line did, and which commits were applied. Creates are recorded before they are sent, so even a write whose response was lost is never forgotten. The agent reads the receipt, not its own last tool call.sponson init adopts existing resources as { keep: true }: Sponson takes over that they exist, keeps their live values, and never destroys them.--env production without --approved-by is refused before any adapter is touched, and so is any run with a line that writes to production (a Vercel target: production, a LaunchDarkly environment that is production). The default environment is always preview; nothing is inferred from a branch name.sponson apply --destroy removes what Sponson created, in reverse order, and never touches resources it merely adopted. A resource Sponson created that someone edited since (changed drift) is deleted too, since the pull request is closing, but never silently: the output, the PR comment and the receipt () name it.Sponson manages per-environment state at 64 providers in 13 categories, from deploy targets and databases to auth callbacks, feature flags, webhooks and DNS: 17 first-class ops and 68 recipe ops. sponson init detects 59 of them from a repository's files and writes their lines.
docs/providers.md lists every one: what Sponson manages there, the op or recipe, the credential, what init detects it by and a line to start from.
Install the CLI from npm (Node.js 22 or later):
npm install -g sponson # or run it without installing: npx sponson <command>
To run an unreleased commit instead, run it from source (the workspace packages resolve to their TypeScript
sources, so it runs through the tsx loader rather than a build):
git clone https://github.com/MishaBear94/Sponson ~/sponson && (cd ~/sponson && pnpm install)
alias sponson="node --import ~/sponson/node_modules/tsx/dist/loader.mjs ~/sponson/packages/cli/src/bin.ts"
Then, in your app's repository:
sponson init --setup # detects the stack, writes release.plan.yaml, then sets up each provider's token (below)
sponson plan # read-only diff
sponson apply # creates the branch, injects the variable, waits for the deploy
--setup turns the plan into credentials you can run it with, in one pass in your own terminal. For each provider the
plan uses it shows the page where the token is created and the least it needs, takes the token from the environment
or asks for it (hidden input, never written to disk), and checks it with one read-only request. Then, after a yes for
each, it stores the checked tokens as GitHub Actions secrets of your origin with your own gh (the value goes to
gh secret set on stdin, nowhere else), and writes .github/workflows/sponson.yml with the action pinned to the
commit of the installed version's release tag (an existing file is never overwritten). TODOs the plan still has (a
placeholder such as a project id init could not find) are listed first, and the workflow is not offered until they
are filled in: it would run a plan that cannot work. A default the plan runs with but you should look at (a recipe's
documented default, such as Stripe's webhook path, marked # CHECK:) is listed as "please check" and blocks nothing.
Run it again any time, also on an existing plan; --yes accepts every offer for scripted use, --json reports what
init detects (todo and check), each credential's status without a value, and next: { command, why }, where
command is the command to run next (sponson plan once ready, sponson init --setup when a token only needs to be
typed) or null when the next step is not a command (filling in a TODO, making a new token), and why says what to do.
Agents ask a human to run it rather than handle a token themselves (SKILL.md).
$ sponson init --setup
Wrote release.plan.yaml
Added .sponson/ to .gitignore
Detected: Vercel (.vercel/project.json), Neon (package.json: @neondatabase/serverless), Clerk (package.json: @clerk/nextjs), Next.js (package.json: next)
Credentials for release.plan.yaml:
Neon NEON_API_KEY
create it: https://neon.com/docs/manage/api-keys
pick: A project-scoped API key for the one project (an organization admin creates it); otherwise a personal API key.
Sponson calls Neon with this key; it is Sponson's credential, not one of your app's variables.
NEON_API_KEY (input hidden, Enter to skip):
ok: GET /projects/proj_demo (reaches project proj_demo)
Vercel VERCEL_TOKEN
create it: https://vercel.com/account/tokens
pick: A token whose Scope is the team that owns the project, with an expiration.
Sponson calls Vercel with this token; it is Sponson's credential, not one of your app's variables.
VERCEL_TOKEN: from the environment
ok: GET /v9/projects/prj_demo (reaches project prj_demo)
Clerk CLERK_SECRET_KEY
create it: https://dashboard.clerk.com/last-active?path=api-keys
pick: The Secret Key of the instance whose redirect URLs the plan manages (sk_test_ for development); Clerk secret keys have no scopes.
Sponson calls Clerk with this key; it is Sponson's credential, not one of your app's variables.
CLERK_SECRET_KEY (input hidden, Enter to skip):
unauthorized: clerk: GET /redirect_urls?paginated=true&limit=1 → 401: {"error":"chaos"}
GitHub Actions secrets of acme/web (with your `gh`; the value goes to its stdin only):
Store NEON_API_KEY as an Actions secret of acme/web (replaces one of that name)? [y/N] y
NEON_API_KEY: stored
Store VERCEL_TOKEN as an Actions secret of acme/web (replaces one of that name)? [y/N] y
VERCEL_TOKEN: stored
CLERK_SECRET_KEY: not offered (no value, or it did not check ok)
Write .github/workflows/sponson.yml (the action pinned to the commit of sponson@<version>)? [y/N] y
Workflow: wrote .github/workflows/sponson.yml (action pinned to 3f1c0a9e7b2d, sponson@<version>).
Not ready yet: Fix the credential that did not check ok (Clerk: unauthorized), then run `sponson init --setup` again and `sponson plan`.
To try Sponson first without any account, against a local fake cloud: `npx --yes @sponson/sim --demo sponson-demo`
<version> is the installed version; the commit is the one its release tag points at.
Where each provider's token is created and what to pick is listed per provider in docs/providers.md.
sponson init reads the repository's files only (no network, no credentials): .vercel/project.json and
vercel.json, netlify.toml and .netlify/state.json, package.json dependencies, Prisma and Drizzle configs,
.neon, and the variable names in
.env.example, .env.local and the other .env* files. It never reads a value out of them, except to recognise a
database host such as *.neon.tech. It writes a line only for what it found (one database: a Neon branch, a PlanetScale branch and
password, or a Supabase preview branch, in that order of preference when several are detected; the Vercel or Netlify preview
variable that references it under the name your code reads; a Clerk redirect or a Supabase Auth redirect for the
preview URL), fills in the project ids it can find, and marks each one it cannot with a TODO comment saying where to
look (vercel link, netlify link, neonctl projects list, supabase link). LaunchDarkly gets a commented example line to fill in with a
flag key and uncomment. A Wrangler configuration (wrangler.toml, wrangler.json) gives a Cloudflare Pages
variables line with the project's name; Pages preview variables are shared by every preview, so no per-PR value
is wired into them. A provider managed by recipes gets its recipe's line, ready when the plan has
everything it needs and commented out with a TODO otherwise. With nothing detected it writes the Vercel + Neon
template. Besides the plan, init writes one line, .sponson/ (where local receipts go), into .gitignore.
A service init detects that no adapter or recipe manages yet is listed as "not supported yet", with where to ask for it (or why no API can manage it), and never silently dropped: today Pusher Channels and Liveblocks.
$ sponson init
Wrote release.plan.yaml
Added .sponson/ to .gitignore
Detected: Vercel (.vercel/project.json), Neon (package.json: @neondatabase/serverless), Clerk (package.json: @clerk/nextjs), Next.js (package.json: next), Prisma (package.json: @prisma/client)
To fill in:
providers.neon.project (now "proj_xxx"): run `neonctl projects list`, or https://console.neon.tech → your project → Settings → General → Project ID
Next: fill in the TODOs, set VERCEL_TOKEN, NEON_API_KEY, CLERK_SECRET_KEY in your environment, then run `sponson plan`
Receipts: each `sponson apply` records what it did on an orphan branch of this repository (`sponson-receipts/<env>/<scope>`, never merged), so the next run, on any machine or in CI, sees drift and knows what to destroy.
A value is filled in once its # TODO comment is gone too: until then it counts as a placeholder. sponson init --json reports the same under detected (also on a re-run with --setup, where todo is what the plan still has):
found and unsupported (each with its evidence), todo (each placeholder's path and hint) and assumed (true
when the plan starts from the template). Paths are relative to the working directory in text and absolute in JSON.
Which providers are covered today, and what is planned, is measured in docs/coverage.md.
Beyond the built-in adapters, any JSON REST API is reachable with the generic http adapter, and the providers it
has been verified against ship as recipes: one plan line names a provider operation and fills in
its params, for example recipe: cloudflare.dns_cname with a zone_id, a name and a target. Each recipe cites the
API docs it was checked against and runs through create, re-apply, drift and destroy in the test suite.
Third-party adapters and secret sources load as plugins: SPONSON_PLUGINS=sponson-adapter-x,./local-adapter.mjs, each module exporting register(registry).
Credentials come from the providers' own conventions (VERCEL_TOKEN for Vercel; every adapter's variable is listed under built-in ops). Sponson has no credential store of its own: sponson init --setup checks them and hands them to GitHub's.
In GitHub Actions, one workflow with three triggers calls the same action:
on:
pull_request: { types: [opened, synchronize, closed] }
deployment_status:
permissions: { contents: write, pull-requests: write, deployments: read }
jobs:
sponson:
runs-on: ubuntu-latest
# only finished preview deployments; production has its own approved job (see action/README.md)
if: >-
github.event_name == 'pull_request' || (github.event.deployment_status.state == 'success' &&
github.event.deployment.environment != 'Production' && github.event.deployment.environment != 'production')
env:
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
NEON_API_KEY: ${{ secrets.NEON_API_KEY }}
CLERK_SECRET_KEY: ${{ secrets.CLERK_SECRET_KEY }}
steps:
- uses: actions/checkout@v4
# full history lets Sponson recognise a late build of an older commit
with: { ref: "${{ github.event.deployment.sha || github.sha }}", fetch-depth: 0 }
- uses: MishaBear94/Sponson/action@<commit-sha>
with:
command: ${{ github.event.action == 'closed' && 'destroy' || 'apply' }}
The action comments the plan and the receipt on the pull request. See action/README.md.
sponson mcp exposes sponson_plan, sponson_apply and sponson_receipt over stdio. SKILL.md tells an agent when to write a plan line, when to stop and show a human the diff, what partial and blocked mean, and why it must never write a secret value or approve production itself.
Every command (init included) takes --json, and every outcome, failures included, is one JSON document: { ok, command, ... } or { ok: false, command, error: { code, message } }. That holds for a mistyped flag (USAGE), a plan error, a provider failure (PROVIDER_*) and an unexpected crash (INTERNAL) alike, and the MCP tools return the same envelope as the first line of every result. ok is true exactly when the exit code is 0. Pending, secret and sensitive values are null next to an explicit state, never placeholder text; display strings exist only in the human-readable output. Secrets are masked in every form a provider may echo them (raw, JSON-escaped, URL-encoded, base64, the password inside a connection string) before anything is printed, logged or written to a receipt, and JSON is masked field by field so redaction can never change its structure.
plan and apply also take --format markdown: the pull request comment the GitHub Action posts (what the preview has, what waits, what to fix, and on destroy what was cleaned up and kept), for any CI or agent that wants to post it. The sponson package exports the same renderer, renderMarkdown(envelope), for a --json result already in hand.
Copy-paste setups beside the GitHub Action, each with its prerequisites, the variables to set and the token that lets it push receipts (overview):
on_stop job
destroys the preview when the merge request is merged or closed.release.plan.yaml ──▶ sponson plan ──▶ diff + drift (reads adapters, writes nothing)
└──▶ sponson apply ─▶ receipt (dependency order, rollback on failure)
│
┌───────────────┼────────────────┐
▼ ▼ ▼
neon.branch vercel.env clerk.redirect_allow
│
── deploy ── external event: stop, record `waiting`,
│ resume on the next apply
▼
preview_url ──▶ callback
A plan is a flat list. Each line is one adapter op, filtered by environments:. Order is derived from references. Every value has a state (literal, resolved, pending, secret or kept), and the JSON output carries it explicitly so an agent never has to parse prose.
Receipts live on an orphan git branch so CI runs, which start from nothing, can still see what the last run did. The store is an interface; local is the alternative, and a hosted one is where a control plane would plug in.
This repository was built and accepted entirely against a local fake cloud, because no real provider account was available during development.
packages/sim serves the API subsets the adapters use, with a chaos endpoint: latency, failing or hanging the next N requests matching a rule, 429 with Retry-After, lost responses after a successful write, pagination, Neon's asynchronous operations, deployment lifecycles, and console-style drift (edit, delete, delete-and-recreate).scenarios/ holds the acceptance scenarios: one YAML file per failure mode (anywhere under scenarios/, grouped by failure family such as mid-run failure, concurrency, drift, secrets, the deploy barrier and mistakes agents or humans make), each run end to end through the CLI by scenarios/runner.test.ts.scenarios/journeys/ holds long system tests, one directory per dimension: among them a week of a team's CI lifecycle, many actors at once on real git receipts (including SIGKILL mid-apply), providers misbehaving like real clouds, an agent driving Sponson only through MCP and JSON, humans editing consoles and refactoring plans, and every channel a secret could leak through (including the receipts branches' history and PR comments).property/ generates random plans, failures (including lost responses) and drift, and checks the invariants numbered at the top of property/engine.property.test.ts, among them that plan writes nothing and that nothing Sponson created survives a successful destroy, over hundreds of generated cases per run (SPONSON_PROPERTY_RUNS sets how many).What the fake cannot prove is that the real APIs behave as assumed. The assumptions are numbered at the top of each provider's routes file in packages/sim/src/routes/, each marked verified or unverified.
gitSource missing the required repository id and Neon connection strings hard-coded to a new project's database and role names. docs/api-verification.md has the per-call tables, sources and dates.423 while a branch is created, whether a Neon branch being deleted still lists, which status Clerk gives a duplicate redirect URL, whether LaunchDarkly accepts re-adding a target its variation already serves, and how long a Supabase preview branch takes to come up. scenarios/contract.test.ts pins the critical ones: it runs against the sim by default and against the real APIs with pnpm test:live (see the file header for the required variables). It has not yet been run against real accounts.Format, engine, the built-in adapters and secret schemes, local and git-branch receipt stores, CLI, MCP server, GitHub Action, templates for GitLab CI/CD, CircleCI and Bitbucket Pipelines (run end to end in Docker against the fake cloud by scripts/try-ci-templates.sh: GitLab's through gitlab-ci-local, CircleCI's and Bitbucket's job by job in their images with the hosts' variables emulated; not yet run on the hosts themselves). Which providers are supported, and how to start with each: docs/providers.md. Not yet: LaunchDarkly rules (its individual targets are supported), a hosted approval inbox, garbage collection of scopes whose PR closed without the action running.
plan and an apply run through the code, the ledger, scopes, redaction.release.plan.yaml, value forms, ${ctx.*}, the built-in ops.Editors with the YAML language server validate and complete the plan file from its JSON Schema. Add this as the first
line of release.plan.yaml:
# yaml-language-server: $schema=https://raw.githubusercontent.com/MishaBear94/Sponson/main/schema/release.plan.schema.json
See CONTRIBUTING.md for the full adapter checklist: the adapter file, its registration (or a plugin loaded with SPONSON_PLUGINS), one sim routes file, and one scenario. Adding a recipe is one YAML file; its checklist is there too.
Apache-2.0.
notes.changedOutsidemanual.step line (a Google OAuth redirect URI for the preview URL) shows its instructions as a todo, holds back the lines that depend on it until someone runs apply --confirm <line>, records who confirmed it and when, and asks for its undo on destroy. Agents show the step to a person; they never confirm it.