agentleFS
stefanprodanstefanprodan/1ctx/AGENTS.md

1ctx

AGENTS.md8 starsChanged 25 days agoApache-2.0View on GitHub

One continuous context for agents. Domain: 1ctx.dev. 1ctx is a self-hosted server where users chat with AI agents in projects and run them on schedules (automations), with shared knowledge and memory. - Runtime: Bun only, TypeScript run directly, one standalone binary. No Node. - Packages are devDependencies bundled at build time: exact pins, official npm only, bun install --ignore-scripts. A new package needs the user's explicit go-ahead. In src/, only server/lib/archive.ts imports @zip.js/zip.js and modern-tar, only server/email/smtp.ts imports nodemailer, only…

  • Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.

    Of the AGENTS.md files we read, the 31,843 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.

  • In this repository2 other files it gives its agents.

The file

We split this AGENTS.md into the rules it gives an agent

7 rules. About 1 is common, 1 is distinctive, and 5 are very specific to this project.

  • ≈1

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 5

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    No import cycles between files, type-only imports included.

    line 195
  2. Very specific:

    Every stylesheet opens with @layer tokens, base, owners.

    line 200
  3. Very specific:

    Only client/ui/Split.tsx writes the aside's line classes (split-line, split-item, split-note and their parts).

    line 208
  4. Distinctive:

    No test names a real provider host.

    line 213
  5. Very specific:

    Access is enforced in the router and nowhere else: Every route carries a policy: public, authenticated, admin or webhook.

    line 220
  6. Common:

    Never a secret, message, prompt, description, tool input or output, query string, raw path, file name or text, email, attempted login name, …

    line 254
  7. Very specific:

    UI copy is short and plain: No em-dashes anywhere. A send (one pass of the runner, docs/sessions.md) is a turn in a chat and a run in an …

    line 279

≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
AGENTS.md

1ctx

One continuous context for agents. Domain: 1ctx.dev. 1ctx is a self-hosted server where users chat with AI agents in projects and run them on schedules (automations), with shared knowledge and memory.

  • Runtime: Bun only, TypeScript run directly, one standalone binary. No Node.
  • Packages are devDependencies bundled at build time: exact pins, official npm only, bun install --ignore-scripts. A new package needs the user's explicit go-ahead. In src/, only server/lib/archive.ts imports @zip.js/zip.js and modern-tar, only server/email/smtp.ts imports nodemailer, only server/mcp-server/ imports @modelcontextprotocol/server, and only client/ui/Plot.tsx imports uplot. patches/ holds modern-tar's patch: it keeps the raw header typeflag, so GNU sparse and unknown types are not read as regular files, and cancelling an entry's body never drops the next entry's, which hung the stream.
  • just-bash is ours. Its source lives in vendor/just-bash/ and we change it; vendor/README.md says how.
  • Status: alpha. The API and the socket change freely, with no shims. Stored data is kept (see migrations below).

The dev loop

Everything goes through the Makefile; each target runs the package.json script of the same name.

make preview        # (re)start the local preview on 127.0.0.1:1236, hot reload
make preview-stop   # stop it
make preview-log    # tail its log
make preview-clean  # stop it and wipe its db, secrets, log and pid
make preview-provision FILE=x.yaml  # stop it, apply the objects, start it
make preview-reset FILE=x.yaml SECRETS=dir  # wipe it, copy the secrets in, provision
make start ARGS="..."  # run the source in the foreground with the server's flags
make dev ARGS="..."    # the same with ONECTX_DEV=1 and a restart on server changes
make clean          # preview-clean, then remove bin/ and Bun's build leftovers
make lint           # biome check --write, then bun check; run after any code change
make test           # bun test; run after any code change, before finishing
make vendor-test    # just-bash's own suite, against its expected failures
make build          # standalone binary in bin/
make smoke          # start the binary, sign in over HTTP, stop it (CI runs it)
make image          # the container image, native and loaded; PLATFORMS=a,b only builds
make image-smoke    # run the image as production does, sign in, stop it (CI runs it)
make kind-up        # the local kind cluster 1ctx-test; kind-image, kind-down
make staging-deploy     # build main, back the staging db up, swap the binary, restart
make staging-provision FILE=x.yaml [SECRETS=dir]  # stop staging, apply, start
make staging-status     # what the staging service says
make load-db PRESET=bench|small  # a load test database in scripts/load/out/
make load-bench ARGS="..."  # compare builds under load; load-cluster on kind, load-summary
make models         # refresh src/server/providers/models.json from models.dev

The preview is a local, throwaway instance for trying a change. It runs the source with ONECTX_DEV=1 against .preview/1ctx.sqlite and the secrets in .preview/secrets/. A CSS edit hot-reloads, a client edit reloads the page, a server edit restarts the process. The first start writes user-admin.key with the password admin-preview. Check a UI change in Chrome through the DevTools MCP at 1440 and 390 wide; the console must stay empty. Report what was verified and how. Do not commit unless asked.

Staging is a long-running instance on a separate machine, used for real work, so its data is kept; docs/deploy.md says how it is run.

Layout

src/shared/   wire contracts and guards: contracts/, api/<area>.ts,
              socket.ts, words.ts. No bun:, node:, DOM or package
              imports. Only what crosses the wire, never a row.
src/server/   the binary. main.ts (flags, db, secrets) calls compose.ts,
              the composition root: areas in layer order, their ports,
              the route list, the router. lib/ (http, body, errors, log,
              clock, ids, bus), db/ (open, transact, migrations/), then
              one directory per area.
src/client/   the Preact app from client/index.html: app/ (routes,
              router, shell), data/ (api, entity cache), lib/, ui/
              (primitives, each with its stylesheet), transcript/,
              composer/, feed/, agents/, views/<area>/, style/.
test/         invariants/ (cross-cutting suites), server/, client/,
              shared/, vendor/just-bash/, structure.ts (the layout
              rules), helpers/, fixtures/.
scripts/      preview, staging, smoke, image, release, vendor-test and
              cloud-setup (a Claude Code cloud environment) scripts;
              brand.py; record/, the fixture recorders, run by
              hand; load/, the load harness (docs/load-testing.md).
skills/       installable agent skills, added by URL, never seeded;
              the binary embeds and serves external-tasks/.
site/         1ctx.dev and the brand files, its own project.
              site/README.md is the brand book.
vendor/       just-bash/ (a git subtree, outside Biome and the structure
              rules) and its three docs.
docs/         the rules of each area (see Docs).
deploy/       docker/ (the Docker Compose files), charts/onectx/ (the Helm
              chart) and flux/ (its Flux example); docs/deploy.md.

Server areas. src/server/<area>/ has index.ts (what others may import, and the factory <area>Area(deps), the one place its store is built), store.ts (<Noun>Store), routes.ts, parse.ts (the request parsers) and named files for logic. A module declares each port it needs as its own small interface; compose.ts passes what the factory of the area that answers it returns for that port. A port to an area built later is a closure called only after the list is complete. An edge the layer order forbids is a port, never an import. A test of one area builds it with its factory and fakes for its ports; test/helpers/app.ts calls compose(), so the integration tests run the binary's wiring.

Workers. A *.worker.ts is an extra entry of bun build --compile in package.json's build script. Its URL is built in compose.ts, since a relative URL inside the binary resolves against src/server.

Test helpers. test/helpers/app.ts wires the server over a test db with a fake clock, the least argon2id cost, a cookie jar and a fake fetch that answers only the recorded hosts (PROVIDER_URL, GEMINI_URL, NIM_URL, GROQ_URL, KEV_URL, MLX_URL, AZURE_URL, ANTHROPIC_URL) and fails every other, a scripted CHECK_URL host (checkHost()), and a fake email sender that

keeps every message; sleeping, slept and commandPhase await the fake clock and a command's phase. In chat.ts, until, idle, freed, sessionSettled and ringing await bus events, sends letting go and the fake clock's due sleeps. smtp.ts is a fake SMTP server on loopback. chat.ts drives a chat with a scripted provider stream. auth-cases.ts is the authorization matrix.

Docs

The files under docs/ and vendor/ are rules with the same force as this file. Read the one that covers a change before making it, and change it in the same commit as the code that changes a rule.

DocGoverns
docs/ui.mdsrc/client/: data layer, primitives, forms, themes, helpers
docs/shell.mdthe shell, the rail and its Recent list, the drawer, the installed app, app links and /knowledge/ paths in replies
docs/views.mdwhat a page draws: views/, the session list (feed)
docs/project-settings.mda project's repositories and MCP servers lists, on its Settings tab and admin page
docs/channel-page.mda project channel's page: quotes, pending turns, the context line, its pages and gap
docs/composer.mdcomposer/: the draft, its files and switches, the slash commands
docs/external-task-pages.mdwhat the external task pages draw: the tab, the task's page, its timeline, Home's card
docs/admin-pages.mdwhat the admin pages draw: views/admin/, lists, object pages, drafts, saves
docs/access.mdrequests and the router, logins, users, names, project visibility, secrets, the socket, links by email
docs/providers.mdproviders/, deciders/, an agent's provider, model and thinking
docs/wires.mdthe azure and anthropic wires: their bodies, streams, catalogs and adapted refusals
docs/sessions.mdsessions/ and the runner's sends (a chat's turns, a run): caps, writer, stream bounds
docs/channel-context.mda channel turn's snapshot, traces, stream budget, admission and meter, run posts, a clear
docs/queue.mdmessages to a busy chat: the queue, its dispatcher
docs/subagents.mdthe delegate tool, child sessions, the child loop and the child rows
docs/compaction.mdthe summary round, its max_tokens, the tail after a summary, compact on demand
docs/archive.mdarchive, agent retirement, packing, the sweep, the kept files job
docs/memory.mdmemory/, memory_edit, a run's memory phase
docs/automations.mdautomations/, the scheduler, the check URL, what only runs do
docs/attention.mdthe attention mark (agent, runner, decider backup), the open alert and its email
docs/external-tasks.mdexternal-tasks/: member routes, task delivery and maintenance
docs/tools.mdtools/, credentials/, skills/, limits/, the tool loop, visuals, email_user
docs/project-tools.mdthe automation and external_task tools
docs/mcp.mdmcp/, MCP tools in a send, MCP results kept as files
docs/mcp-server.mdmcp-server/, the inbound /mcp endpoint and its tools
docs/knowledge.mdknowledge/, uploads
docs/images.mdimages/: the image store, ingest, its limits, serving, access, the lease, the agent's image flag, the claim at send, the budget, queued and forked images, image lines, the wires' image parts, the token estimate, the check, images in history, a message's images on the page
docs/search.mdshared/search.ts, knowledge search, session search and list
docs/repos.mdrepos/: repositories, their hosts, names and credentials
docs/email.mdemail/: the SMTP server, the outbox, the sender, agent and alert email, the SMTP page, the pages of email links
docs/dictation.mddictation/: the Dictation setting, POST /api/transcribe, its WAV check, cap, call and usage row
docs/bash.mdbash/, the bash tool, open, scratch, kept MCP files, curl signing
docs/monitor.mdoverview/: what the admin Monitor pages read, the usage windows
docs/provision.mdprovision/: applying YAML objects, --provision
docs/deploy.mdservice/, staging, the container image, deploy/, release and CI
docs/load-testing.mdscripts/load/: the load harness, its fakes, databases, fence, targets and results
vendor/README.mdchanging or syncing vendor/just-bash/
vendor/changes.mda hunk of vendor/just-bash/: its (1ctx <id>) entry, same commit
vendor/differences.mdwhere a vendored command still differs from its tool

Rules the structure test enforces

test/structure.ts is the source of truth; every rule has a rejected fixture under test/fixtures/structure/.

  • shared/ imports only shared/. client/ imports client/ and shared/. server/ imports client/ only in main.ts, for the page.
  • Server areas have a layer order (LAYERS in the test). An area imports only areas above it, through their index.ts or rules.ts. web/ imports only access and lib, and nothing imports web/, main.ts or compose.ts. The server root holds only main.ts and compose.ts, which may import every area. Moving an area is a change to LAYERS in the same commit.
  • A rules.ts (an area's pure rules) or a *.worker.ts never loads db/ or an area's index.ts, so workers stay small (WORKER_EXEMPTIONS lists the exceptions).
  • No import cycles between files, type-only imports included. Dynamic imports are string literals, never a template with ${}. Every import carries its extension.
  • A production file over 500 lines fails unless listed in LINE_EXEMPTIONS with a reason.
  • Every stylesheet opens with @layer tokens, base, owners; and puts every rule in a layer (UNLAYERED lists the exceptions, with reasons). style/tokens.css and style/base.css are unique names. Any other sheet has a unique name and owns that class prefix (rail.css styles .rail-*). It styles a base.css primitive only inside its own selector, and never selects by element, attribute, id or * at any depth, inside :is(), :has(), :where() and :not() too.
  • Only client/ui/Split.tsx writes the aside's line classes (split-line, split-item, split-note and their parts).
  • Colour, font family, font size, the font shorthand and radius come only from tokens.css: never a literal anywhere else, CSS or TSX, a var() fallback included (LITERAL_EXEMPTIONS lists the exceptions).
  • No test names a real provider host; the suite never reaches a network.
  • AGENTS.md and each docs/*.md stay under MAX_DOC_TOKENS (5,000 o200k tokens). A doc near the cap is cut, or split by topic with a row in the Docs table, never trimmed of a rule to fit.

Rules the code follows

  • Access is enforced in the router and nowhere else. Every route carries a policy: public, authenticated, admin or webhook. A handler gets a typed Principal and never reads a header. Every new route gets a row in test/helpers/auth-cases.ts, or the access suite fails. The rest of the rule (same origin, parsers, body caps, login limits) is in docs/access.md.
  • Routes never overlap. Two patterns of one method that could match one path fail the router at start (conflicts() in web/router.ts).
  • Writes that belong together go through transact(). The body returns its result and the bus events, published after the outermost commit and never on a throw, so nesting is safe. Bus events are hints; a subscriber reads rows for the truth.
  • A schema change is an appended migration, renames and retypes included; a store never creates a table. A migration on main, or one that ran on staging, is never edited, and no database is wiped: staging holds real data. Widening a check rebuilds the table in place (create, copy, drop, rename) and keeps the rows.
  • A rebuild of a referenced table sets rebuild: true and names its tables in rebuilds, copying every row with its key unchanged. migrate() turns foreign keys off around the transaction, since the pragma cannot change inside one and a drop would cascade, then throws when a named table's row count changed or foreign_key_check finds a row.
  • Secrets are files, one bare value per <kind>-<name>.key, read through the secrets port bound to the caller's kind. A value is never logged, returned by a route or stored in the database (docs/access.md).
  • Session is the domain noun and never means a cookie; the cookie is a login.
  • A log line is one slog text event on stderr, from logger(area) in lib/log.ts. Messages are fixed lowercase phrases; fields are flat and duration is whole milliseconds. Fields hold only ids, usernames, configured names and models, route patterns, counts, statuses, closed words, durations, client addresses, error fields and startup paths. Never a secret, message, prompt, description, tool input or output, query string, raw path, file name or text, email, attempted login name, body or socket reason.
  • Errors are logged through errorFields(), which keeps the first line (cut at 200 characters, with live keys scrubbed) and the source frames. A ToolError logs its fixed logged phrase, never its message.
  • The router logs a request for a signed-in user's writes and 4xx answers and for any 5xx; a successful key route is the exception because its MCP tool logs the call. Never log an anonymous 4xx, health or ready. Refreshes and sweeps log only work done or a failure. A test collects events with collectLogs(), passing its logFactory to testApp().
  • Pure logic is separate from I/O and tested on fixtures; a bug is recorded as a fixture before it is fixed.
  • Tests in a file run concurrently. A test that sets module state (a signal, globalThis.fetch) or counts bus events is test.serial. Linux CI runs the files in parallel, each in a fresh global, so a test sets what it reads itself. Local runs take the files one by one. A test's clock counts its neighbours' work, so the default timeout is 20 s. No test asserts elapsed time or lets a real sleep, timer or poll budget decide it: a fake clock, an awaited event or counted work. A promise that may never settle takes a plain await, never expect(p).rejects or .resolves, where Bun's timeout never fires.
  • Comments explain why, never what. Style is Biome's: 2 spaces, double quotes, semicolons, trailing commas, 80 columns.
  • UI copy is short and plain. No em-dashes anywhere. A send (one pass of the runner, docs/sessions.md) is a turn in a chat and a run in an automation; the page never says send.
  • perl -i -pe for global replaces, uv run for ad hoc Python, never pip.
  • The brand SVGs and PNGs in site/ are generated: change scripts/brand.py or the numbers in site/README.md and regenerate.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.