aimono
v0.1.1
Published
An Nx monorepo built to be operated by AI agents: every app ships with an AGENTS.md that is generated from the project graph, not written by hand.
Maintainers
Readme
aimono
Drop an AI agent into a monorepo it has never seen and watch what happens. It greps around for
a while, finds a package.json, and runs npm test in the root because that's the command it
knows. In an Nx workspace that's the wrong command, and the agent has no way to find out except
by failing.
The usual fix is to write an AGENTS.md by hand. That works for about three weeks. Then someone
renames a target, someone else adds an app, and the file quietly starts lying. A lying AGENTS.md
is worse than no file at all, because now the agent trusts it.
aimono takes the part of that file which can be derived and derives it. Targets, commands,
paths, tags and dependencies come out of the Nx project graph. Everything a person knows and a
graph doesn't stays in a region the tool never touches. A check in CI fails the build when the
derived part goes stale, so it can't rot without someone noticing.
What you get
npx aimono new acme # Nx workspace with Biome, Husky and a root AGENTS.md
cd acme
npx ai app web --type=next # an app that ships with its own AGENTS.md
npx ai sync # rewrite every generated region from the graph
npx ai sync --check # exit non-zero if any of them is staleai is a thin alias over Nx. ai app web --type=next is nx g aimono:app web --type=next, and
you can use either. Nothing is hidden behind the alias, which matters when an agent needs to
compose a command the alias doesn't cover.
The file it writes
<!-- ai:generated -->
# web
Nx application (next) rooted at `apps/web`.
## Commands
| Target | Command |
| --- | --- |
| build | `nx build web` |
| serve | `nx serve web` |
| test | `nx test web` |
<!-- /ai:generated -->
## Decisions and traps
Anything below this heading belongs to whoever works here. `ai sync` never touches it.
The importer runs single-threaded on purpose. The upstream API rate limits at 10 rps.Everything between the markers is regenerated. Everything outside survives byte for byte, and
that's enforced by tests, not by good intentions. Write what you learned the hard way under
## Decisions and traps, because that's the half a project graph can never tell you.
How staleness is caught
ai init registers the generator in nx.json under sync.globalGenerators, so nx sync and
nx sync:check pick it up like any other Nx sync generator. The Husky pre-commit hook runs the
check, and so should your CI. If a target gets renamed and nobody reruns ai sync, the commit
fails and says which file drifted.
Why Biome and not ESLint
One process instead of two, and the Nx generators are pointed at linter: none so they don't
install the pair. ai init and ai app both delete a .prettierrc if a wrapped generator
writes one, because they do, and a formatter that reflows markdown tables will fight the sync
check forever. That fight is covered by an end-to-end test.
Use npm 11, or pnpm
npm 10 crashes with Cannot read properties of null (reading 'edgesOut') while resolving the peer
set that the Nx app generators pull in, somewhere around vitest and vite. It is a bug in npm's
arborist, not in Nx and not here, and it reproduces on a plain npm install with no generator
involved. The nasty part is the aftermath: the install dies half done, and the next Nx command
fails with something unrelated-looking from the project graph. ai new and ai app check your npm
version and say so before you lose an hour to it.
Status
Version 0.1. It creates workspaces, generates next and node apps, and keeps every
AGENTS.md honest. Libraries, more frameworks and adopting an existing workspace aren't in yet.
Requires Nx 21 or newer and Node 20 or newer.
License
MIT
