acryl
AGENTS.md337 starsChanged 54 days agoMITView on GitHub
This repository owns the desktop product around an unmodified DeepSeek Harness checkout. The agent's system prompt (where it comes from, how to change it, and a generated current copy per surface): docs/system-prompt/README.md. Building or changing an ACRYL plugin, tool, UI slot or skill: start at plugins/acryl-plugin-context/docs/README.md (routed docs) and plugins/acryl-plugin-context/example-plugins/README.md (verified examples for every plugin type). Where an ACRYL app keeps anything (home, engine home, port, Electron user data, project folders): only through the AppInstance family in runtime/acryl-harness-runtime/src/instance/ (chosen once…
- Installs packages
We split this AGENTS.md into the rules it gives an agent
21 rules. About 0 are common, 8 are distinctive, and 13 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈8
Distinctive · estimate
This author's own choices. Worth a look.
13
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 13
Use Node.js ^22.19.0 or >=24.0.0 and the root PNPM 11.11.0 release through Corepack.
- Very specific: line 19
Start the isolated local Desktop (own ~/.acryl-dev home, advanced mode, Development Canvas) with corepack pnpm run dev (alias: corepack …
- Very specific: line 20
Use corepack pnpm run dev:shared only when you intentionally want the installed app's ~/.dsh home.
- Very specific: line 26
Run upstream operations through the root scripts, such as corepack pnpm run upstream:build.
- Distinctive: line 35
Keep graphical application launch explicit.
- Distinctive: line 37
Commit every important coherent change promptly so regressions can be reverted to a precise checkpoint.
- Distinctive: line 39
Commit before major changes of direction and keep the submodule pin update separate from desktop behavior changes.
- Distinctive: line 40
Keep the repository topology and package-manager split consistent with the owning Agent Note.
- Very specific: line 44
Before changing a plugin, service, tool, provider, event hook, Host route, Client contribution, or Loader composition, read …
- Distinctive: line 51
Before implementation, write the Cordis mini-design in the active plan or research note:
- Very specific: line 83
Use function plugins by default and Service classes for direct named capabilities.
- Distinctive: line 95
Treat PENDING as valid missing-dependency state.
- Very specific: line 127
Do not mutate durable/system state from a presentation surface, and do not encode internal state bits into user-visible names or fields (no …
- Distinctive: line 191
Prefer identity (IDs) over object references across aggregate/context boundaries.
- Very specific: line 211
Keep the spec ledger honest: when a delivered interaction diverges from spec.md / plan.md / tasks.md, update the ledger (or open a decision …
- Very specific: line 224
Default Matt Pocock roles: needs-triage, needs-info, ready-for-agent, ready-for-human, wontfix.
- Very specific: line 250
Run graft map first — a token-budgeted orientation (dir clusters, hubs, hotspots), no LLM, no key.
- Very specific: line 253
Run graft ask "<your question>" --source → ranked nodes with the relevant code spans inlined (each hit's ≤8-line crux by default.
- Very specific: line 265
Add --direction out for what it calls, or --depth N to walk transitively for the full blast radius.
- Distinctive: line 273
If a returned span is truncated ("+N more lines"), open the file at that exact range before finalizing.
- Very specific: line 278
After big code changes, refresh the graph with graft build (deterministic, no API key, $0).
≈ “Common” is an estimate: at least 1 in 5 of the 36,368 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.
Files
DSH Desktop repository rules
This repository owns the desktop product around an unmodified DeepSeek Harness checkout.
The agent's system prompt (where it comes from, how to change it, and a generated current copy per surface): docs/system-prompt/README.md.
Building or changing an ACRYL plugin, tool, UI slot or skill: start at plugins/acryl-plugin-context/docs/README.md (routed docs) and plugins/acryl-plugin-context/example-plugins/README.md (verified examples for every plugin type).
Where an ACRYL app keeps anything (home, engine home, port, Electron user data, project folders): only through the AppInstance family in runtime/acryl-harness-runtime/src/instance/ (chosen once by select.ts, read by plugins from the appInstance service). Never call homedir() or read ACRYL_HOME/DSH_HOME/ACRYL_WEB_PORT anywhere else; tests/bulkhead.spec.ts enforces it. Design and rules: docs/acryl/APP-INSTANCES-AND-BULKHEADS.md.
Prerequisites and setup
- Use Node.js
^22.19.0or>=24.0.0and the root PNPM11.11.0release through Corepack. - Initialize the pinned upstream checkout with
corepack pnpm run upstream:sync. - Install root dependencies with
corepack pnpm install --frozen-lockfile.
Build, run, and verify
- Start the isolated local Desktop (own
~/.acryl-devhome, advanced mode, Development Canvas) withcorepack pnpm run dev(alias:corepack pnpm run desktop) orcorepack pnpm run local. - Use
corepack pnpm run dev:sharedonly when you intentionally want the installed app's~/.dshhome. - Fast headless loop:
corepack pnpm run typecheck,corepack pnpm run test, or both viacorepack pnpm run verify. - Typecheck, test, then isolated GUI:
corepack pnpm run lifecycle. - Build the desktop package with
corepack pnpm run build. - Build an installable Desktop for the host you are on:
corepack pnpm build:mac(unsigned DMG for this Mac's CPU only,apps/acryl-desktop/dist/mac-<arch>, about 0.7 GB installed;build:mac:universalbuilds both CPUs intodist/mac-smoke, about 1.2 GB installed),corepack pnpm build:windows(NSIS installer),corepack pnpm build:linux(Debian.deb,apps/acryl-desktop/dist/linux-<arch>). Each needs its native OS; the signed and notarized macOS release isdist:macand needs a Developer ID certificate in the Keychain. - Run the complete headless gate with
corepack pnpm run check. Every package's build wipes and rewrites itslib/in place, so two builds in one checkout collide (a package that depends on the one being rebuilt cannot find its output for a few seconds): run a gate or any long build asnode scripts/with-build-lock.mjs corepack pnpm run check; the launchers (pnpm web,pnpm acryl, Desktopdev) take the same lock around their build and wait for each other. - Run upstream operations through the root scripts, such as
corepack pnpm run upstream:build. deepseek-harness/is a pinned upstream Git submodule. Never edit files inside it from a desktop feature branch.apps/acryl-desktop/owns the Cordis Host and Client faces, Electron bootstrap, packaging, and release tests.plugins/dsh-community-fabric/owns the community interoperability RFC. Until schemas and a reviewed reference adapter exist, it remains a private documentation scaffold and must not declare loadable DSH or package entry points.plugins/cordis-plugin-market/is an implemented private Host/Client package. It is an optional Desktop Market provider, disabled by default, and must continue to use ordinary DSH/Cordis, profile, and Desktop service contracts rather than a parallel plugin runtime.- The outer repository and all owned packages use the root PNPM release with
node-linker=isolated. - The upstream submodule keeps its own PNPM workspace. Run upstream commands through the root
upstream:*scripts, which enter the submodule before invoking its pinned Corepack release. - Compatibility mode must run the upstream default client without overrides. Advanced presentation belongs to desktop-owned client plugins and may replace documented slots or services through profile composition.
- Keep graphical application launch explicit. Builds, typechecks, unit tests, and Loader smokes must remain headless-safe.
- During the current small-team rapid-development phase, work directly on
mainunless the user explicitly requests a branch or pull request. Do not create routine PRs. Third-party contributors on forks should always work on a feature branch and open a PR upstream — the "work on main" convention applies to maintainers with push access, not to fork-based contributors. - Commit every important coherent change promptly so regressions can be reverted to a precise checkpoint. Prefer several focused commits over rare large snapshots.
- Record every important product, architecture, workflow, or operational evolution in
docs/DEVELOPMENT-LOG.md. Commit the implementation first, then add its full canonical commit hash and human-readable explanation to the log in a separate documentation checkpoint. Update logged hashes after any history rewrite or squash. - Commit before major changes of direction and keep the submodule pin update separate from desktop behavior changes.
- Keep the repository topology and package-manager split consistent with the owning Agent Note.
Cordis development protocol
Before changing a plugin, service, tool, provider, event hook, Host route,
Client contribution, or Loader composition, read
docs/cordis/cordis_system_guide_for_coding_agents.md.
Then inspect the owning pinned Harness subsystem documentation and package
types/source. The local vendored Harness behavior is authoritative over generic
Cordis examples.
Before implementation, write the Cordis mini-design in the active plan or research note:
- Capability and plugin boundary — what domain owns it and why it needs independent lifecycle/configuration/replacement.
- Provides and consumes — services, tools, events, durable facts, hard
injectrequirements, and intentionally optionalctx.get()dependencies. - Effects and disposal — every activation-owned resource, its disposer, required cleanup order, cancellation, and quiescence behavior.
- Configuration and composition — validated runtime schema, stable Loader row ids, scopes/isolation, and provider replacement behavior.
- Events and durability — dispatch mode, explicit waterfall
next()semantics, and which replay-critical facts belong in durable session state. - Verification — real Loader activation plus PENDING/reactivation, provider replacement, disposal, repeated mount/reload, and leak checks.
Loader row id naming. A Loader row's id (what include: prefixes)
must equal its package name by default — acryl-development-canvas gets
row id acryl-development-canvas, never an unrelated shorthand a reader
has to look up in the package's own cordis.patch.yml to decode (fixed
real instances of the anti-pattern: acryl-development-canvas itself
shipped with row id desktop-development-canvas until this rule was
written; acryl-dsh-editor-plugin's row id is the still-unfixed, opaque
dsh-editor, discovered only when it broke Desktop's boot — neither was
a hypothetical). The one legitimate
exception is a deliberately shared, multi-provider slot where the id names
a capability, not a package, because more than one interchangeable
package can fill it (e.g., the brand-slot pair, where ui-brand-official
and dsh-client-ui-brand-acryl both occupy the same swap slot by design).
That exception must be named as such in the mini-design (point 4 above) —
it is never a default excuse for an unrelated or abbreviated id.
Use function plugins by default and Service classes for direct named
capabilities. Consumers depend on stable service interfaces through inject,
not concrete providers or YAML row order. Cordis/Harness registrations are
lifecycle-owned; raw timers, watchers, sockets, PTYs, subprocesses, routes, and
subscriptions are acquired inside one owning ctx.effect() and fully released
by its disposer.
A Harness Tool is a consumer of ctx.tools, not a Cordis primitive. Tool
plugins inject tools, register with defineTool(...), return canonical typed
values separately from model/UI rendering, honor exec.signal, traverse the
normal policy pipeline, and disappear when their owning Fiber unloads.
Treat PENDING as valid missing-dependency state. Current Fiber states are PENDING, LOADING, ACTIVE, FAILED, UNLOADING, and DISPOSED. A provider change must unload and reactivate consumers without stale references or duplicate registrations. Cordis service isolation scopes resolution; it is not an OS sandbox.
Architecture and clean-code discipline (engineering books)
Engineering reference (authoritative for clean-architecture, DDD, and day-to-day engineering-discipline judgement; this section is the ACRYL-specific interpretation):
~/.agents/rules/agent-rules-books/clean-architecture/clean-architecture.md~/.agents/rules/agent-rules-books/implementing-domain-driven-design/implementing-domain-driven-design.md~/.agents/rules/agent-rules-books/the-pragmatic-programmer/the-pragmatic-programmer.md
Precedence: the constitution, the Cordis coding-agent guide, and the ACRYL control-surface design win over this section; this section never overrides a documented seam or an owning-package contract. These are coding-style and boundary-discipline rules, not a second architecture.
Boundaries
- Surfaces (
acryl-tui, Electron, Web) render and drive runtime semantics; they do not own domain or business logic. ACRYL-owned capability logic belongs behindacryl-control/acryl-harness-runtimecontracts. Never implement a provider/credential/authorization state machine, a durable-state write, or a business invariant inside an overlay or surface file. - Depend on typed service interfaces (
injectkeys and typedctx.get(...)), never onany, bare framework handles, concrete providers, or YAML row order. Aconst svc: any = ctx.get('x')in production code is a review failure (break the pattern with an explicit decision, or fix it; do not extend it). - Do not mutate durable/system state from a presentation surface, and do not
encode internal state bits into user-visible names or fields (no
-oauthdisplay-name suffixing). A presentation field is not a domain store. - Cross-boundary data flows through one typed projection/service, not through
ad-hoc re-fetch plus
refreshCredentialState()-style shotgun loops. One source of truth per state; targeted invalidation or subscription, not "refresh everything".
Repository layout (package placement discipline)
Root packages are grouped by role, not left flat (fixed real instance:
ten packages sat loose at repo root with no grouping signal for what
depended on what — acryl-npm-launcher, a release shim, sat at the same
level as acryl-harness-runtime, the core engine, and cordis-plugin-market,
a Cordis plugin; regrouped 2026-09-14, pnpm-workspace.yaml and
scripts/verify-layout.mjs are the enforced source of truth for the
result). This is Clean Architecture ch.11 (dependency inversion — depend
inward, never let the stable core depend on a replaceable surface) and
ch.17 (plugin architecture — components a reader should recognize as
swappable belong grouped, not scattered) applied to directory layout, not
just import direction. It is also Pragmatic Programmer's broken-windows
discipline: one un-grouped, randomly-placed package normalizes the next
one, and a repo that looks abandoned gets treated like one.
Current groups and what belongs in each:
apps/— the swappable surfaces (acryl-cli,acryl-web,acryl-desktop). A new terminal/web/desktop-shaped entry point goes here.runtime/— the stable core every surface depends on (acryl-control,acryl-harness-runtime). Nothing here may depend on anything underapps/.plugins/— independently replaceable Cordis/DSH plugins (dsh-client-ui-brand-acryl,dsh-community-fabric,cordis-plugin-market). A new installable capability package goes here, not next toapps/orruntime/.examples/— demo/reference packages (acryl-blend-demo) that ship nothing production-facing.distribution/— release/publish shims (acryl-npm-launcher), never product logic.deepseek-harness/(pinned submodule),docs/,specs/,scripts/,patches/,assets/stay at root — they are not workspace packages.
A new top-level package's home is decided by which of the five groups it
plays the role of, not by where it's convenient to drop it "for now" —
there is no scratch space at root. If a new package genuinely fits none
of the five, that is a signal to design the grouping deliberately (raise
it, don't invent a sixth ad hoc bucket) — the same discipline this
section already asks for Loader row ids and service contracts. Whichever
directory a package moves to or is added under, update it in the same
commit as pnpm-workspace.yaml's package list and
scripts/verify-layout.mjs's asserted layout — the CI gate
(corepack pnpm run check) is the actual enforcement, this text is only
the reasoning behind it.
Models and language
- Model real domain concepts with small, immutable, explicit types (value
objects / discriminated unions), not bare
string/'a' | 'b'unions smeared inline. One exported type per concept; do not re-declare it in three files. - One term, one meaning (ubiquitous language). Do not overload a single field
(e.g.
configured) to mean different things in different overlays. Rename when understanding improves; keep tests, events, commands, and services speaking the same language. - Prefer identity (IDs) over object references across aggregate/context boundaries; keep aggregates small and centered on immediate invariants. Protect the core domain from generic abstractions and vendor terms.
Functions and state
render()/ UI projection functions are pure — no state mutation during render. View state is a small discriminated-union state machine, not a loose field cluster that can drift inconsistent.- Extract genuinely shared logic once (e.g. list-window slicing) into a narrow,
owned helper; do not build generic
utils/,shared/, orcore/dumping grounds. - Depend inward: framework/infrastructure details at the edge, business rules in the application/domain layer.
Checkpoints and honesty
- Land coherent, buildable commits. A
HEADthat cannot typecheck (a feature split so its container is committed but its surface is not) is a review failure — restore a green, reversible checkpoint. - Keep the spec ledger honest: when a delivered interaction diverges from
spec.md/plan.md/tasks.md, update the ledger (or open a decision ticket) before marking the slice done. Never leave a stale spec apparently active.
Agent skills
Issue tracker
Decisions and feature specs live as markdown under specs/ (Spec Kit + Wayfinder). See docs/agents/issue-tracker.md.
Triage labels
Default Matt Pocock roles: needs-triage, needs-info, ready-for-agent, ready-for-human, wontfix. See docs/agents/triage-labels.md.
Domain docs
Single-context. Constitution, orientation, Cordis spec, and docs/acryl/ are required reading; CONTEXT.md / ADRs are created lazily. See docs/agents/domain.md.
Local Cordis plugin quick-build
Need a Cordis plugin for your own immediate use, not public distribution? Use the cordis-plugin-quickstart skill (.claude/skills/cordis-plugin-quickstart/SKILL.md) to scaffold, mount, and hot-iterate one locally instead of going through cordis-plugin-market's npm-publish install path.
Agent-runtime, Development Canvas, context-relay, and third-party adapter work must follow docs/acryl/AGENT_CONTROL_SURFACE_CORDIS_DESIGN.md and the current alignment audit. Build on Cordis services, injection, effects, events, Fibers, Loader composition, and existing DSH capability seams; do not introduce a parallel lifecycle, dependency-injection, event, tool, or provider framework.
Rebuilding the graft graph
Use corepack pnpm run graft:deepscan, never a bare graft build --deep. Graft 0.18.0 cannot finish a DeepSeek deep pass unpatched (it stalls at ~80% with empty-parsed on ~175 files); the script re-applies the four required patches and then builds. corepack pnpm run graft:deepscan -- --check verifies the setup and writes nothing. A graft upgrade or reinstall reverts those patches, so re-run the script after either. Rationale and measurements: docs/DEVELOPMENT-LOG.md, 2026-09-14.
<!-- graft:start -->Graft — repo context graph
This repo is indexed in graft/: small linked markdown nodes that explain each
system and carry exact file:line spans, kept in sync with the code through git.
For ANY task here — understanding how something works, finding where code lives,
or scoping a change — get context from the graph before grepping or opening
source files. Re-ask freely (it's cheap) and reuse literal identifiers you
already have (symbol, error string, file name) as the query. New to this repo?
Run graft map first — a token-budgeted orientation (dir clusters, hubs,
hotspots), no LLM, no key.
- Run
graft ask "<your question>" --source→ ranked nodes with the relevant code spans inlined (each hit's ≤8-line crux by default;--fullfor whole definitions when the crux isn't enough). Match the tool to the task shape: for understanding or editing, the top node IS the answer — cite itscovers:file:line spans and edit straight from--source. For exhaustive tasks ("every occurrence / every caller of this pattern"), ranked results are top-N, not complete — rungraft grep "<literal>"instead (exhaustive over indexed files, grouped by enclosing symbol), falling back to rawgrep -rnonly for unindexed files. graft skeleton <file>→ every definition's signature + span, ~10× cheaper than reading the file; use it to skim an API surface.graft callers <symbol>gives precomputed, exact edges — who calls this. Add--direction outfor what it calls, or--depth Nto walk transitively for the full blast radius. For structural questions, skip ranking and use this directly.- Or browse:
graft/INDEX.mdlists every node; follow the links. - Monorepos and folders of multiple repos rank fairly across sub-projects —
hits carry
[scope/]labels naming which one they're from. Narrow withgraft ask "<task>" --in <scope>/once you know where you're working.
If a returned span is truncated ("+N more lines"), open the file at that exact range before finalizing. Only open source files when a node genuinely lacks a needed detail, and then at the exact file:line the node points to — never re-read whole files.
After big code changes, refresh the graph with graft build (deterministic,
no API key, $0).
<!-- graft:end -->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 28,693 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 repository21 other files it gives its agents.
- .github/copilot-instructions.mdCopilot instructions
- speckit-analyzeSkill
- speckit-checklistSkill
- speckit-clarifySkill
- speckit-constitutionSkill
- speckit-convergeSkill
- speckit-implementSkill
- speckit-planSkill
- speckit-specifySkill
- speckit-tasksSkill
- speckit-taskstoissuesSkill
- speckit-analyzeSkill
- speckit-checklistSkill
- speckit-clarifySkill
- speckit-constitutionSkill
- speckit-convergeSkill
- speckit-implementSkill
- speckit-planSkill
- speckit-specifySkill
- speckit-tasksSkill
- speckit-taskstoissuesSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
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.

