Seed is one public repository, github.com/seed-hypermedia/seed, holding the Go daemon, the TypeScript apps and libraries, the agent runtime, the vault, deployment tooling, and the markdown for this site. This page is for people who want to change any of it. It covers the layout, the one-command development stack, the checks each area expects before a pull request, and the rules for the changes that are hard to undo: storage migrations, protocol changes and releases.
Every command below was checked against the repository on branch feat/onyx in September 2026. The repository also keeps instructions for coding agents in AGENTS.md at the root and in the subtrees listed below. They are written for humans too, and they are the authoritative version of the rules summarized here.
The repository
Path | What lives there | Toolchain |
|---|---|---|
| the Seed daemon: storage and indexing ( | Go, built with Please |
| protobuf definitions for every daemon service; generated Go and TypeScript are checked in | Please, |
| the Seed app (Electron) | pnpm |
| the Seed web app that serves sites, the Seed API and site services (Remix) | pnpm |
|
| pnpm workspace, runs under Bun |
| the email notification service | pnpm |
| pnpm | |
| the React Native app, outside the pnpm workspace | npm |
| the landing site, email templates, performance tooling | pnpm |
|
| pnpm |
| shared models and hooks ( | pnpm |
| the Seed Agents server | its own Bun workspace |
| its own Bun workspace | |
| this site: concept pages, the Hypermedia Schemas library, the Seed API reference, the Agents docs | markdown, |
| the self-hosted node deployment script ( | pinned Bun |
| cross-app integration tests | pnpm, Vitest, Playwright |
| internal design notes, decision records, runbooks and the security audit log; not published | markdown |
agents/ and vault/ copy the frontend packages they use through file: dependencies, so a change to frontend/packages/* reaches them only after bun install. Their dev servers re-sync automatically. The map pages under The Seed software, such as Daemon, Desktop and Web, explain how the programs talk to each other.
Setting up
The toolchain versions are pinned in mise.toml and activated by direnv.
Install mise and direnv and hook direnv into your shell, then clone the repository and allow the environment. The first direnv allow installs the pinned tools, initializes the llama-go submodule, downloads the embedding model and builds the llama.cpp libraries, which takes a few minutes.
git clone https://github.com/seed-hypermedia/seed
cd seed
direnv allow
pnpm installInstall Docker as well if you want the full stack, because the agents' web search backends run as containers.
./dev refuses to run outside a direnv-enabled shell. From scripts and agents, run commands as direnv exec . <command>.
Running things
./dev with no arguments lists every command. The ones you will use:
Command | What it does |
|---|---|
| the whole stack on mainnet in one mprocs window, one pane per process (see |
| the same stack on the dev testnet (see |
| the desktop app, which builds and spawns its own daemon |
| the desktop app on mainnet |
| build and run |
| production builds |
| the desktop test suite |
| build |
| edit a markdown folder, |
| check generated code and regenerate what is stale |
| format the whole workspace, then check formatting the way CI does |
./dev up starts these panes:
Pane | Process | Address |
|---|---|---|
| SearXNG and crawl4ai containers for agent web search | :8899, :11235 |
| the Seed Agents server with hot reload | :3051 |
| the web app, talking to the desktop app's daemon | :3000 |
| the Hypermedia Explorer | :5173 |
| the notification server | :3060 |
| the vault | :3030 |
| the Electron app on mainnet with its daemon | daemon HTTP :58001 |
| the round trip between |
In mprocs, r restarts the focused process, s stops it, x starts it and q quits everything. Quitting also runs docker compose down for the search containers. The development daemon uses ports 58000 to 58004. The full port table is on Network.
Root package.json scripts start single apps: pnpm web, pnpm desktop, pnpm notify, pnpm explore, pnpm mobile, and pnpm web:standalone, which runs a web app against its own daemon.
Checks before a pull request
Run the checks for every area you touched. CI runs the same ones, and a single unformatted file anywhere fails the Lint job.
Area | Commands |
|---|---|
Whole TypeScript workspace |
|
Formatting, everywhere |
|
Web, shared, desktop unit tests |
|
SDK, UI, editor, notify, explore |
|
| |
Desktop end to end |
|
Integration |
|
Mobile |
|
Agents |
|
Vault |
|
Dependencies |
|
Go |
|
Docs |
|
In agents/ and vault/, bun check runs the type checker and rewrites formatting, so commit whatever it changes. Go tests need the submodule and model that direnv allow fetched. CI runs them with go test -tags cpu --count 1 ./backend/.... For backend bug fixes, add a failing test first when practical, and use testify/require in Go tests.
To reproduce CI locally before pushing, use agent-ci. docs/local-ci-with-agent-ci.md has the guide.
npx @redwoodjs/agent-ci run -w .github/workflows/test-frontend-parallel.yml -p --github-token
npx @redwoodjs/agent-ci run -w .github/workflows/lint-go.yml -p
npx @redwoodjs/agent-ci run -w .github/workflows/test-go.yml -pChanges with special rules
Storage schema and migrations
The daemon's SQLite schema lives in backend/storage/schema.sql, which is the source of truth, and migrations live in backend/storage/storage_migrations.go. Read the comment at the top of that file before adding one. The rules it sets:
A migration's version is a timestamp from date +%Y-%m-%d.%H%M%S, and the list is kept newest first.
Its run function executes in an immediate write transaction and must be as idempotent as possible.
A migration runs only when its version is higher than the data directory's, so never run a feature branch with a migration against a data directory you care about. Back it up first. Switching back to main afterwards fails on the unknown version.
After changing the schema or migrations, run ./dev gen //backend/....
Avoid migrations that force a full reindex or recompute embeddings unless you must. CPU-only servers take a long time to redo them. Prefer an additive column and a bounded background backfill.
When in doubt, ask the backend team before adding a migration. Tag the Go daemon maintainers on pull requests that touch backend/.
Protobuf and generated code
Edit .proto files under proto/, then run ./dev gen //proto/... from the root. Do not run buf or protoc directly, and do not format the generated code. Proto changes ripple into Go and TypeScript callers, so run the backend and frontend checks above. gRPC describes the services for API consumers.
Protocol changes
A protocol change is any change to the structure or meaning of permanent data (blobs, changes, the document graph, the CRDT rules), the sync protocol, the capability model, the identity system, or any format another implementation must read on disk or over the wire. A feature that can be built purely in an application is not a protocol change. The team's advice is to build it that way first.
The team's process for a protocol change, as written in its internal methodology notes:
Write a proposal note describing the problem and the change.
Map the arguments for and against it in the open, including rejected alternatives.
Decide by working through the technical objections. Consensus does not decide.
Update the protocol documentation, which is now this site.
The process is slow on purpose because published blobs are permanent. Every node that holds old data must keep reading it. Where this is going shows what this looks like in practice.
Deployment tooling
ops/ is built with the exact Bun version pinned in ops/package.json, and CI fails if ops/dist/deploy.js is stale. Rebuild it with that version, as bunx --bun bun@<version> build …, whenever you change the deploy script.
Releasing
Maintainers cut releases with the runbook in docs/releasing.md.
Pick the version YYYY.M.N: the year, the month without zero padding, and the next number within the month. Check recent tags with git tag --sort=-creatordate | head -5.
Tag the release commit, normally the tip of main, and push the tag. A *.*.* tag starts the Release - Desktop App and Release - Docker Images workflows.
Wait for the desktop workflow to build every platform and create the GitHub release as a prerelease.
Write short, user-facing release notes with Features and Bug Fixes sections and a full-changelog link, then publish them with gh release edit <tag> --notes-file <file> --prerelease=false --latest.
Run the Generate latest.json (prod) workflow so desktop auto-update sees the new version.
Contributing to these docs
This site is the hypermedia/ folder, and a commit to main publishes it through .github/workflows/sync-hypermedia.yml. Pages are plain markdown with a name and a one-sentence summary in the frontmatter. Links between pages are relative .md links. The dialect round-trips losslessly through the Seed app. hypermedia/README.md explains the layout, and Publish a folder explains the round trip.
node scripts/hypermedia/check.mjs # schemas, lockfile, generated types, bindings, frontmatter
pnpm hypermedia:push -- --dry-run # what a publish would create, update, move or retire
./dev hm-sync # edit the folder in the desktop dev app and write edits backRules that matter when you edit:
Nothing publishes while any relative link is broken, so fix links in the same commit that moves a page.
Renaming a file in git publishes a move with a redirect at the old address.
Deleting a file retires its document on the next push, unless the push runs with --keep-stale.
A page with a *.schema.json beside it defines a schema. Keep its path, and let check.mjs confirm the lockfile and generated types.
Keep the <!-- id:… --> comments on lines you keep. They are block ids. New pages need none.
Corrections are welcome as pull requests, or as comments on the published page.
Reporting security issues
Report security issues by email to security@hyper.media. Do not open a public issue or pull request about an unfixed vulnerability. This repository is public.
Once a vulnerability is fixed, the team discloses it as a GitHub issue closed by the fixing commit. The public record of what has been audited and which hypotheses were ruled out is docs/security/audit-log.md, and the audit procedure itself is docs/security/auditor.md. The known limits you should design around, such as the unauthenticated local daemon API and non-revocable capabilities, are listed on Integrity.
See also
The Seed software, a map of every program in the repository.
Getting started, for using Seed without changing it.
Self-hosting, for running a site.
Where this is going, for the design context behind a protocol change.
Publish a folder, for how these docs round-trip.
Daemon gRPC, for the services the protobuf files define.
Do you like what you are reading? Subscribe to receive updates.
Unsubscribe anytime