Using & hosting Chainstitch
Everything you need to go from git clone to a running notebook — and from your laptop to a team instance. The README on GitHub stays the full reference.
Quick start
npm install npm run dev
Open http://localhost:3000 — a fresh instance boots with an Example project (Ethereum mainnet via a public RPC) whose Welcome notebook is a runnable tour of blocks, variables, conditions and recipes: open it and hit Run all, no contracts and no wallet needed. The SQLite database creates and migrates itself; there is no other setup. Every project you create seeds the same tour against its own RPC — there's an Anvil preset for local chains, or point it at any endpoint. Delete the example when you're done.
A wallet is only needed for write blocks. Injected wallets (MetaMask, Rabby, …) work out of the box; for WalletConnect set NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID (see .env.example). Reads and RPC calls run without any wallet, straight from your browser.
Projects & contracts
A project is one chain config: chain id, RPC URL and optional block explorer. Its Contracts tab is the address book every notebook, codegen flavor and State card reads from.
Add contracts by fetching a verified ABI — paste an address and the lookup queries Sourcify and Blockscout (Etherscan too when the server sets ETHERSCAN_API_KEY; a free key covers 60+ chains) — or by dropping ABI JSON files(raw arrays or Foundry/Hardhat artifacts). Proxies are handled automatically on lookup: the implementation ABI is paired with the proxy address, via explorer hints or an EIP-1967 slot read. On an anvil fork, pick the chain the fork is based on in the lookup's chain select.
Notebooks & blocks
Notebooks run like Jupyter: per-block or top-to-bottom, with outputs decoded and saved. Name a block's output and reference it downstream as {{pool}} or {{receipt.blockNumber}} — dot/bracket paths reach into structured results.
| Block | What it does |
|---|---|
| Read | Calls a view/pure function from the address book, args from a typed form. |
| Write | Simulates first — revert reasons surface before the wallet prompt — then sends and awaits the receipt. |
| RPC | getBlock, getBalance, getLogs, … plus a raw custom-method escape hatch for anvil cheatcodes. |
| Text / Variable | Markdown notes, and named constants usable as {{chips}} anywhere. |
| Sender group | Runs child blocks as a chosen caller (impersonation on anvil needs no keys). |
| If group / run-when | Blocks run only when a condition on prior outputs holds ({{allowance}} < {{amount}}). |
| Recipe cell | Reruns a saved recipe's steps in one click — see below. |
Keyboard shortcuts follow Jupyter: B adds a block, M a markdown cell, Shift+Enter runs and advances, Cmd+Enterruns in place. Notebooks and recipes open in browser-style tabs above the editor; each project's Overview page manages its documents.
Recipes
Select blocks in any notebook and bookmark them as a named recipe — the classic is check the allowance, approve only if it's too low. Insert one from the add-block menu either as a linked recipe cell (one click reruns every step; cells follow when the recipe is edited) or as editable blocks. Recipes live in the sidebar under your notebooks and open in the same editor: tweak steps with the full typed forms, test-run in place, then Save to publish.
State tab
Pin view functions (name, totalSupply, slot0, …) per contract into a live dashboard — one multicall fetches everything, refreshed on demand. Drag cards to rearrange, drag an edge to resize, drop in section titles.
Codegen & AI import
Every block deterministically generates its source — wagmi hooks, viem, Python (web3.py), Rust (alloy) or Solidity — with ABIs and addresses pulled from the address book. A notebook-level toggle shows the full runnable source, and the whole notebook exports as a JSON call manifest. The notebook is the integration spec you hand to the frontend, and it can't drift because you just ran it.
AI import converts a Foundry .t.sol test into runnable blocks: vm.prank becomes a sender group, vm.deal/vm.warp become cheatcode cells, asserts become condition checks. Bring your own Google AI Studio key (free tier) — calls go straight from your browser to Google and never touch the Chainstitch server.
Local chains & forks
anvil # plain local chain anvil --fork-url $RPC # fork mainnet/testnet state
Point a project at http://127.0.0.1:8545 (chain id 31337). The custom RPC block drives cheatcodes — anvil_setBalance, anvil_impersonateAccount, evm_snapshot, evm_revert — and sender groups impersonate whales on forks without touching a private key. Write blocks sent by an impersonated sender need no wallet at all.
Team mode & self-hosting
Same codebase, same database, one environment variable apart:
| local (default) | team | |
|---|---|---|
| Sign-in | none | Sign-In with Ethereum (SIWE) |
| Who gets in | whoever can reach the port | invited wallets only |
| Sharing | — | by wallet address, with roles |
| Best for | your laptop, trusted networks | a team instance on a server |
Team mode needs four variables (see .env.example):
APP_MODE=team OWNER_WALLETS=0xYourAddress # comma-separated owners BETTER_AUTH_SECRET=$(openssl rand -base64 32) # session signing key APP_URL=https://notebook.example.com # exact URL users visit
Serve it over HTTPS behind any reverse proxy (sessions and SIWE messages are domain-bound to APP_URL), start with docker compose up -d --build or npm run build && npm start, sign in with an owner wallet, and invite teammates from Settings(the gear button). Invites are just a wallet address and a role — no email server — claimed on that wallet's first sign-in.
| Role | Can do |
|---|---|
| viewer | read everything, run blocks with their own wallet |
| editor | + edit contracts, notebooks, blocks, state views |
| owner | + project settings & RPC URLs, members & invites, deletes |
Share at whichever radius fits: the workspace (Settings → invite), a single project (its Share button — grantees see nothing else), or an anyone-with-the-link URL(viewer or editor, no account; resetting the link revokes every copy). Note that project access includes the project's RPC URL, since blocks execute in each member's browser — use rate-limited keys for shared projects.
Never expose a local-mode instance to the internet — it has no auth by design. Private keys never touch the server in either mode: writes are signed in the browser, reads run client-side, and the server stores notebook definitions, never execution results.
Security & your data
Chainstitch is built so the scary things can't happen by construction, not by policy:
| Invariant | What it means |
|---|---|
| Keys never touch the server | Writes are signed in your own browser wallet. There is no server-side signing capability at all, in any mode. |
| Execution is client-side | Reads, writes and RPC calls go straight from your browser to your RPC endpoint. The server never proxies chain traffic. |
| Results are never stored server-side | The database holds notebook definitions (projects, ABIs, blocks) — not what they returned when you ran them. |
| Your data is one file you own | Everything lives in a single SQLite file on your machine or server. No telemetry, no license server, nothing phones home. |
Team-mode authentication is Sign-In with Ethereum done carefully: single-use nonces, signatures domain-bound to your APP_URL(a message signed for another site can't be replayed against yours), httpOnly Secure session cookies, and an invite-only sign-in policy — an uninvited wallet cannot even create an account. Signing in costs nothing and touches no chain; it proves wallet ownership, nothing more. Removing a member locks them out immediately.
Authorization is enforced server-side, in one data-access layer that scopes every query by workspace and project role — never just hidden in the UI. Cross-tenant isolation and the role matrix are pinned by regression suites (130+ assertions) that run in CI on every change.
The one trade-off to know about: anyone who can open a project can see its RPC URL, because their browser executes calls against it. Use rate-limited or public RPC keys for shared projects. Share links carry viewer or editor rights only (never owner), are re-validated on every request, and resetting one instantly invalidates every copy.
The server makes exactly one kind of outbound request — the ABI lookup — and it is restricted to a fixed allowlist of explorer hosts, with redirects refused and responses size-capped. Found a hole anyway? Report it privately via GitHub's Security tab — acknowledgement within 72 hours, assessment within 7 days, credit when the fix ships.
Operations
Everything lives in one SQLite file (data/chainstitch.db, override with CHAINSTITCH_DB_PATH). Back it up while running with sqlite3 data/chainstitch.db ".backup backup.db". Upgrades are pull → build → restart; schema migrations apply automatically on boot. Switching an existing local instance to team mode keeps every project; switching back bypasses auth again, so only do that on a machine you trust end-to-end.
Deployment guides (Docker, Node, Caddy, backups) live in the README's self-hosting section.