Skip to content

Add shared knowledge ​

Your repo's knowledge base sees only itself. When you want it to draw on knowledge another repo publishes - a shared knowledge base such as the Engineering11 foundation, or a team's standards repo - you declare a dependency with alloy add. This page is the reference for that command: the locators it accepts, what it writes, how a fresh clone restores it, and how a key resolves once more than one knowledge base is in scope.

alloy add in one line ​

bash
alloy add @engineering11/alloy

alloy add does three things in one command, like npm install: it declares the dependency, fetches it into the machine cache, and pins the exact resolution. If the added knowledge base declares its own dependencies, each is offered (default yes) rather than pulled in silently.

Locators: a package or a git URL ​

The argument is either a package or a git URL.

bash
# package - resolves through the @engineering11 registry
alloy add @engineering11/alloy
alloy add @acme/standards@^2.0.0

# git URL - resolves through git, pinned to a ref
alloy add https://github.com/acme/standards.git --ref main
  • A package locator takes an optional npm-style range (@^2.0.0); the registry resolves it to a concrete version.
  • A git locator takes --ref (branch, tag, or commit; default main) and --subtree when the corpus lives somewhere other than .alloy/corpus in that repo.
  • --name sets the local name you qualify keys with (default: derived from the locator). --view picks a view the dependency declares. --save-dev also writes the package into devDependencies for package locators, editing package.json without installing.

Pick from knowledge bases on this machine ​

Alloy remembers every knowledge base it has run in on this machine - each repo where init, sync, status or the MCP server ran - in ~/.alloy/known.yaml (under ALLOY_HOME when set). Run alloy add with no argument in a terminal and it offers them as a multi-select, plus the Engineering11 platform and "Something else…" for a URL or package you type:

bash
alloy add                          # pick from a list in a terminal
alloy add --list                   # print the list
alloy add --list --json            # the same list as a JSON document, for tools
alloy add --pick billing,analytics # add by name (or by path) without a prompt
  • Each ticked row becomes an ordinary alloy add <remote> --ref <branch> --name <name>: the manifest and the lock get a committed git locator, never a local path, so a fresh clone restores it with alloy sync.
  • The remote and branch are read from the repo's working tree each time the list is shown, never stored, so a remote you added a minute ago is already there. The branch is the remote's default branch when git knows it, otherwise the branch checked out.
  • A repo with no git remote is listed but cannot be picked - open it beside this repo instead. A repo already added, one that shares this repo's name, or one whose name is reserved is shown greyed with the reason.
  • Two repos with the same folder name are both listed; pass the path to --pick to say which.
  • --pick checks every value before adding anything: one unknown name and nothing is added. Its own dependencies are offered as usual; off a terminal they are listed, not added, unless you pass --yes.
  • --root <dir> (repeatable) composes the open roots the same way alloy status --root does.

The list is a memory of where Alloy has run, nothing more. It never scans your disk, it never decides what is in scope (only the folders you open and the dependencies you declare do), and an entry leaves it once its folder is gone or no longer holds a knowledge base. When a knowledge base is open beside this repo but not declared, alloy status says so and names the alloy add --pick that makes it permanent.

What lands in the manifest vs the lock ​

Two committed files, two jobs:

  • Intent lives in the corpus manifest's dependencies: block - the human-readable declaration of what this repo draws on, with the range or ref you asked for.
  • Exact resolution lives in .alloy/corpus.lock (lockVersion 2), one entry per dependency: { package, version, view? } for a package, or { git, ref, commit, subtree?, view? } for a git URL.

The fetched content itself lands in the machine cache under ~/.alloy/cache/corpus/<identity>/<version-or-commit>/, which is not committed. Commit the manifest and the lock; the cache is rebuilt on demand.

A fresh clone, and CI: alloy sync ​

Because the cache is not committed, a fresh clone (or a CI runner) has the manifest and lock but no fetched content. alloy sync closes that gap:

bash
alloy sync

It fetches every declared dependency at its exact pin, resolves and locks any manifest entry that has no pin yet, and drops any lock entry the manifest no longer names. Plain sync never re-resolves an existing pin, so CI is reproducible by construction.

Moving a dependency forward is a separate, deliberate act:

bash
alloy sync --update                    # re-resolve every dependency from intent
alloy sync --update engineering11-foundation   # just this one

--update re-resolves the named entries (default: all) from their intent - a package range via the registry, a git ref via ls-remote - rewrites the lock, and prints old → new. It exits 1 listing anything it could not fetch.

Coming from the older single-pin lock? alloy migrate rewrites it into the explicit dependencies: form once.

Check it resolved: the console ​

alloy console is the quickest check that a reference landed: its header shows the scope line an agent would get here, and the Sources screen lists the new source with its declared ref, the pin the lock recorded, and where it is served from (cache, node_modules, or an env override). A reference that cannot be served shows as unavailable with the command that fixes it. If the referenced repo is itself open beside yours (a parent folder holding both), the console serves it from that working tree and reports the pin it is ignoring - the same thing an agent does.

Qualified keys ​

Once more than one knowledge base is in scope, a query key can name which one it means:

<name>/<category>:<unit>

You rarely need the prefix. Your own categories win unqualified, and a category only one other knowledge base declares resolves there on its own. You reach for the qualifier when two in-scope knowledge bases declare the same category and the resolution would otherwise be a loud ambiguity - qualify with the dependency's local name (the --name from alloy add) to say exactly which one.

The scope line ​

Every resolution prints a scope line so you can see what was considered:

[scope] primary=… peers=… deps=… unavailable=… override=…
  • primary - the root holding your working directory; its own categories win unqualified.
  • peers - other open roots composed into the same scope (opening several repos at once unions their corpora).
  • deps - the declared dependencies in scope.
  • unavailable - a declared dependency the cache cannot serve (run alloy sync).
  • override - a declared dependency served from a local path via ALLOY_DEP_PATH_<NAME> instead of the pinned copy (a development convenience; the pin is not being honoured while it is set).

alloy query <key> prints the resolved document, a Cite as line, and this scope line; the MCP server and the knowledge skill resolve the same way. A key in a knowledge base you have not added is out of scope - the error names what is in scope and the alloy add that would bring it in.

E11 Alloy - knowledge as a build artifact.