Get Started
Lightchain Studio Architecture
Lightchain Studio is a build of Code - OSS with Lightchain's own built-in extensions and a few patches to the Code - OSS source. All Lightchain features live in one extension,lightchain.lightchain-studio, written in TypeScript. This page describes Studio 0.1.0. Paths below are relative to the repository.
The pieces
Inside the Lightchain extension: The extension activates on startup. Its compiled bundle (dist/extension.js) is committed, so the IDE runs right after npm run compile.
CodeHTML
Lightchain AI client
src/lightchain/inference.ts is a Node port of the protocol flow the Lightchain AI chat runs in the browser. One instance is one chat session with one worker. It talks to the Lightchain AI server (https://chat-api.testnet.lightchain.ai or https://chat-api.mainnet.lightchain.ai) and its relay (wss://relay.testnet.lightchain.ai/ws or wss://relay.mainnet.lightchain.ai/ws).
Unlike the Developer API, the session key is made and kept in the IDE: the server only ever handles ciphertext of your prompts and answers.
1. Models
GET /api/models lists the models the network serves (name and bytes32 id), and GET /api/workers/availability?models=<ids> gives each one's eligible workers, free slots and status. Studio offers only the models in its coding allow-list (src/lightchain/models.ts).
2. Sign-in
Studio signs in with Sign-In with Ethereum and gets a JWT: The account signs it withpersonal_sign (EIP-191), and POST /api/auth/verify with { message, signature } returns { token, expiresAt }. The token goes to the IDE's secret storage under the key <chainId>:<address> and is reused by every chat until less than a minute of it is left. A 401 from the server drops it, and the next call signs in again.
The server accepts SIWE messages for the domain localhost:3000 only. That is why the wallet bridge serves its page from http://localhost:3000 when that port is free: the wallet then sees a request from the same domain the message names, and shows no domain warning.
3. Session
CodeHTML
- an ephemeral P-256 key pair; ECDH with the recipient's key; the raw 32-byte shared secret (no KDF) is the AES-256-GCM key;
- sealed key =
ephemeralPublicKey (65 bytes) ‖ nonce (12) ‖ ciphertext ‖ tag (16).
src/lightchain/crypto.ts) is vendored unchanged from the Lightchain AI chat and is wire-compatible with the protocol's Go implementation.
4. A prompt
CodeHTML
nonce (12) ‖ ciphertext ‖ tag (16)), uploaded as a blob, and submitted as one job on chain whose fee is debited from your prepaid balance by the server's delegate. A 5xx on submit means the server's submit transaction failed, so nothing was charged; Studio retries once after 2 seconds, and if that fails too, tells you no credits were charged.
Studio sends only the newest message in each job; the worker rebuilds the conversation from the session's earlier jobs. The first prompt of a session also carries the agent's instructions.
5. Streaming
The relay sends JSON frames:chunk, complete, metadata, error, reassignment_required, reassigned, closed. Studio keeps only frames for its job id, decrypts each chunk payload with the session key and streams it into the panel. complete carries the full answer, and ends the job. A chunk with seq 1 after text has arrived means the worker restarted the job, and the stream starts over.
When a worker fails, the panel retries once on another model with free workers, or on a new session for the same model.
Stalled jobs
A job whose worker accepted it and never answered keeps its fee escrowed inJobRegistry. Studio remembers the job ids (src/lightchain/stuckJobs.ts), reads each with getJob(jobId), and simulates settleStuckJob(jobId) to find out whether the contract will settle it yet (it can once the job's deadline plus the resolution timeout, 48 hours today, has passed). Settling is a no-fault exit: the worker is not slashed. Those that would succeed are offered for reclaim; each is one settleStuckJob transaction that returns the fee to your prepaid balance. Jobs that settle in another way are forgotten.
The coding agent
Lightchain models have no native function calling, so the agent (src/agent/agent.ts) uses a text protocol. The system prompt lists the tools, and the model calls one with a fenced block:
CodeHTML
read_file, then write_file with the complete new file, which you approve as a diff. Two habits of small models are handled: a reply that contains a code block and a file name instead of a tool call is turned into a write_file proposal (still approved by you), and a reply that claims a file was created without calling write_file gets one reminder to actually write it.
File tools resolve every path inside the project root and refuse anything that resolves outside it, symbolic links included. run_command runs, after your approval, through your login shell ($SHELL -lc) on macOS and Linux, or cmd.exe /d /s /c on Windows, in the project root.
Wallet
src/wallet.ts holds two kinds of accounts:
- Local: the private key in the IDE's secret storage (Electron
safeStorage, backed by the OS key store), underlightchain.wallet.key.<id>. Signing happens in the extension process with viem. A recovery phrase is used only to derive the key, which is then stored; the phrase is not. - Browser: only the address and wallet name are stored. Every signature and transaction goes through the browser wallet bridge.
confirmMainnet first. On mainnet it estimates the fee and shows a modal confirmation; declining throws before anything is signed.
Foundry keystore export (src/keystore.ts) writes Web3 Secret Storage v3: scrypt (N = 8192, r = 8, p = 1), AES-128-CTR, MAC = keccak256(derived key bytes 16–32 ‖ ciphertext), the parameters Foundry itself writes. The file is created with mode 0600 in ~/.foundry/keystores (mode 0700).
Browser wallet bridge
src/browserBridge.ts connects any browser wallet with no WalletConnect project ID, the same approach as Foundry's --browser mode. Studio runs a small HTTP server on the loopback interface, and the page it serves talks to the wallet extension:
- Origin.
http://localhost:3000when nothing answers on port 3000, elsehttp://127.0.0.1:<port>with a port chosen once and saved, so wallets keep their site permission across restarts. The server binds to127.0.0.1either way. - Token. 256 random bits, created once per install and kept in secret storage; compared in constant time. A wrong token gets
404. - Host and Origin. The
Hostheader must be exactly the bridge's origin (421otherwise), which blocks DNS rebinding. AnOriginheader, when present, must be the same origin (403otherwise), which blocks other sites. - The page is sent with a strict Content-Security-Policy (
default-src 'none', a per-response script nonce,connect-src 'self',frame-ancestors 'none'),no-storeandno-referrer. It finds wallets through EIP-6963, falling back towindow.ethereum. Beforeeth_sendTransactionoreth_signTypedData_v4it callswallet_switchEthereumChain, andwallet_addEthereumChainif the wallet doesn't know the network. It refuses a request when the wallet's accounts don't include the address Studio expects. - Timeouts. A request waits up to 5 minutes for the wallet. If no page is open, Studio opens one and waits up to 90 seconds for it to connect.
The signing proxy
Forge has to send transactions, and Studio must not hand it a key.src/signingProxy.ts starts one JSON-RPC server per deploy and passes it to forge:
CodeBASH
127.0.0.1 on a random port, has a 192-bit random token in its path, answers only POST, and rejects any request that carries an Origin header, so a web page can't reach it. It closes when the forge task ends. Deploy & Verify adds --verify --verifier blockscout --verifier-url <explorer>/api/.
Deployed Programs and Interact
Deployed Programs (src/deployedPrograms.ts) merges, per project and per network:
- Foundry broadcasts:
**/broadcast/**/<chainId>/run-latest.json, everyCREATEandCREATE2transaction and itsadditionalContracts, watched for changes; - contracts created by the deployer address, from Lightscan's Etherscan-compatible API:
GET <explorer>/api?module=account&action=txlist&address=<deployer>&sort=desc&page=1&offset=1000, keeping transactions with notothat did not fail; the last result is cached so the list survives being offline; - addresses you added.
lightchain.programs.scanExclude skipped) for their addresses.
Interact (src/interact.ts) takes the ABI from, in order: the Foundry artifact named like the contract; any Foundry artifact whose runtime bytecode equals the code on chain once the Solidity metadata is stripped; Lightscan's verified source (GET <explorer>/api/v2/smart-contracts/<address>); a JSON file you choose. Reads are eth_call. Writes are first run as eth_call from your account, so a revert shows before you sign.
What Studio stores
The Lightchain extension itself connects only to the Lightchain AI server and relay, the Lightchain RPC, Lightscan's API, the faucet (https://lightfaucet.ai) when you claim from the panel, and the marketplace catalog URL if you set one.
Security model
- Prompts and answers are encrypted end to end. The session key is generated in the IDE and sealed to the selected worker (and the disputer). The server and relay carry only ciphertext.
- Keys stay in secret storage. Local keys are used in the extension process and never reach a web view, the terminal or
forge. Exporting a key or sending a mainnet transaction always asks first. - Forge never holds a key. Deploys sign through the loopback proxy, which only signs
eth_sendTransactionfor the active account and refuses requests from browsers. - The wallet bridge is loopback only, with a per-install 256-bit token and exact
HostandOriginchecks. - The agent asks before it changes anything. It reads and searches the project and runs
forge buildon its own; every file write and every command needs your approval, and it does not run in Restricted Mode. - Credits are capped. The server can spend from your prepaid balance only up to the allowance you set for its delegate, and you can withdraw the balance at any time from your own wallet.
Build from source
You need Node.js 24, Python 3, the platform's build tools for native modules, and Foundry to use the Foundry features.CodeBASH
CodeBASH
v* tag runs the release workflow, which builds every platform and publishes a GitHub Release.