Configuration
Every repository that uses Syllabus has one configuration file, .syllabus/config.yaml. It records the repository’s sources, the rules and skills it includes from each, its exceptions, and where to install skills. A repository whose configuration also has a library section is a library, and publishes its authored rules and skills for other repositories. A repository can be a project, a library, or both, with the same file and the same layout.
Initialize from the repository root. In Git repositories, other commands find the nearest Git root and use its .syllabus/config.yaml. Outside Git, run commands from the repository root. See Working directories.
Sync, build, and check validate the fields below.
Use one YAML document. Duplicate keys, anchors, aliases, and explicit tags are rejected. Quote selectors that start with *, such as "*".
Complete example
Section titled “Complete example”schemaVersion: 2skillTargets: [claude, agents]sources: fabrica: repository: https://github.com/fabricahq/.syllabus.git rules: include: [techs/go/*, practices/testing/*] exclude: - id: practices/testing/table-tests reason: Our test style is documented in CONTRIBUTING.md. pins: - id: practices/testing/verify-retry-limits version: "1.3.0" reason: Waiting on the author's response to fabricahq/.syllabus#45. skills: include: [recommended, skills/deploy-preview] rename: skills/review-change: fabrica-review pstack: repository: https://github.com/example/pstack.git ref: main skills: include: ["*"] uses: skills/architect: [skills/how]This project takes every Go rule and every testing rule from Fabrica’s library except one, and keeps one rule at an older version. It installs the skills Fabrica requires, the ones it recommends, and one offered skill, and installs Fabrica’s review-change skill under another name. From pstack, a repository without a manifest, it installs every skill from the newest commit on main at its last update.
Repository names, rule IDs, and skill IDs in examples are illustrative. Replace them with libraries, rules, and skills your project can access.
Fields
Section titled “Fields”| Field | Meaning |
|---|---|
schemaVersion | Required. 2. See No backward compatibility. |
skillTargets | Optional. Where installed copies of skills go: an array of claude (.claude/skills/) and agents (.agents/skills/). Missing means []. See Skill targets. |
manageAgentsFile | Optional. true, the default, has init, build, sync, and update keep a Syllabus section in the repository’s AGENTS.md, and check verify it. false leaves AGENTS.md alone. See AGENTS.md section. |
sources | Map of stable source names to sources. Use an empty object for a repository that uses only its authored rules and skills. |
sources.<name>.repository | Required. Explicit HTTPS or SSH Git address, including scp-style SSH. See Repository addresses. |
sources.<name>.ref | The branch, tag, commit, or library release to take the source from. Required for a source without release/<number> tags; see Refs. |
sources.<name>.rules.include | Optional rule selectors: rule IDs, prefixes ending in /*, or "*". |
sources.<name>.rules.exclude | Optional list of rules to leave out, each with an id selector and a reason, and optionally a replacement. |
sources.<name>.rules.pins | Optional list of rules to hold at one version, each with an id, a version, and a reason. See Pin a rule. |
sources.<name>.skills.include | Optional skill selectors: recommended, "*", or skill IDs. |
sources.<name>.skills.exclude | Optional list of skills to leave out, each with an id and a reason, and optionally a replacement. |
sources.<name>.skills.uses | Optional map of a skill ID to the skill IDs it calls that its own metadata doesn’t declare. See Declare the skills a skill calls. |
sources.<name>.skills.rename | Optional map of a skill ID to the install name it gets in this repository. See Rename a skill. |
library | Optional. The manifest: what this repository publishes as a library, and the level of each skill it offers. |
Unknown fields are rejected, at every level.
Every part of a source except repository is optional. A source with no include still installs the skills its library requires.
Authored rules, rule groups, and skills are discovered from rules/ and skills/ in the Syllabus directory; they need no configuration entry. See Project files.
Selectors
Section titled “Selectors”The selection from a source is everything its include lists name, minus everything its exclude lists name. Rules and skills each have their own lists, so a rule selector never installs a skill, and a skill selector never includes a rule.
Rule selectors
Section titled “Rule selectors”| Selector | Includes |
|---|---|
practices/testing/verify-retry-limits | One rule, by its ID. |
practices/testing/* | Every rule in the practices/testing rule group, at any depth, including rules the library adds to it later. |
practices/* | Every practice rule, in every practice group. techs/* is every technology rule. |
"*" | Every rule in the source. |
A selector is a rule ID, or a prefix that ends in /*. The * is allowed only at the end, after a /, or alone: techs/go*, techs/*/testing, and ** are rejected. A rule ID names the rule’s path in its library’s rules/ folder, without .md.
exclude entries take the same forms. Use a prefix to leave out a whole rule group that a wider include brings in:
rules: include: [practices/*] exclude: - id: practices/observability/* reason: This CLI has no hosted service to observe.pins take single rule IDs only.
Each rule ID in include must name a rule the source publishes, and each prefix must match at least one rule, except "*". A rule included by an ID and also by a prefix is included once. When a rule brings in its rule group, it brings the rule group’s metadata, so the rule group appears in the generated index with only the included rules.
Skill selectors
Section titled “Skill selectors”| Selector | Installs |
|---|---|
(no include) | The skills the library requires. |
recommended | The skills the library requires and those it recommends. |
"*" | Every skill the source offers, at any level. |
skills/deploy-preview | That skill, whatever its level, plus the required ones. |
Skill selectors have no prefixes: skills/* and recommended/* are rejected. A library’s required skills always install, whatever include says; see Skill levels. A skill a library borrows from another repository is named as the library’s manifest names it, with the borrowed source’s name, such as mattpocock:skills/engineering/to-spec; see Borrowed skills.
exclude entries take a skill ID, recommended, or "*", with a reason. Excluding a required skill fails validation, however the exclusion names it.
Skill levels
Section titled “Skill levels”A library sets one of three levels for each skill it publishes, in its manifest:
| Level | Installed in a project that uses the source when |
|---|---|
| Required | Always, whatever include says. The project can’t exclude or fork it. |
| Recommended | include lists recommended or "*", or names the skill. |
| Offered | include lists "*", or names the skill. |
A library’s own skill that no level lists is offered. A source without a manifest, a non-library source, offers every skill it has and requires none.
A project sees only the levels of the libraries it names as sources. When a library borrows a skill from another library, the project sees the level the borrowing library sets, not the one the original library sets: levels don’t chain.
Because required skills install with no include, a source declared with only a repository installs its library’s required skills, now and after every update that adds one:
sources: fabrica: repository: https://github.com/fabricahq/.syllabus.gitRenaming a required skill is allowed, since it stays installed.
Exclude or replace a rule
Section titled “Exclude or replace a rule”A source’s rules.exclude list leaves rules out of the generated guidance. Each entry records why, and can name an authored rule for agents to read instead:
rules: exclude: - id: practices/testing/avoid-snapshot-tests reason: Contract snapshots follow our separate review policy. - id: techs/typescript/prefer-type-aliases reason: Our public extension API relies on declaration merging. replacedBy: techs/typescript/prefer-interfaces basedOn: "2.0.0"| Field | Meaning |
|---|---|
id | Required. A rule selector. |
reason | Required non-blank text explaining why the repository leaves the rule out. |
replacedBy | Optional, with a single rule ID only. The ID of an authored rule in rules/ that agents read in place of the excluded rule. It must be in the same rule group as the rule it replaces, and each authored rule can replace only one rule. |
basedOn | Optional, and only with replacedBy. The library version of the excluded rule that your rule is based on, in quotes, such as "2.0.0". Forking a rule records the forked version here, and so does replacing a fork with the newest version. Offline commands check only that it’s a version; syllabus project sync checks that the library published that version of the rule, and otherwise fails with version-not-found, listing the versions it did publish. |
An excluded rule is still kept in the source’s vendor snapshot, so you can review its changes. The syllabus project update preview lists a replaced rule as replaced so you can decide whether your rule needs the same change:
- With
basedOn, whenever the library’s newest version of the rule is newer thanbasedOn, whatever version the project includes. The preview lists every change afterbasedOn. To replace your rule with a fork of the newest version, overwriting your edits, passsyllabus project update --update-fork SOURCE:RULE, or answerreplaceto the terminal question; either setsbasedOnto that version. If you merge the changes into your rule by hand instead, editbasedOnto the version you merged. Syllabus never advances it otherwise, because only you know whether your rule took the changes in. - Without
basedOn, such as for a replacement you wrote yourself, whenever the library’s newest version of the rule is newer than the version the project includes, also when a pin holds the vendored copy there. The preview lists the changes since that version, which your rule may already have. Replacing your rule with a fork, as above, also recordsbasedOn.
Exclude or replace a skill
Section titled “Exclude or replace a skill”skills: exclude: - id: skills/write-changelog reason: Release Planner writes our release notes. - id: skills/fix-bug reason: We use our own bug workflow. replacedBy: skills/fix-bug basedOn: "1.0.0"An excluded skill isn’t installed into the target folders or listed in generated/SKILLS.md. A replacement is an authored skill in skills/, named by its skill ID and installed in place of the excluded skill under its own name. Each authored skill can replace only one skill, and a rule can’t replace a skill or the reverse. Forking a skill writes the exclusion for you, with the forked version as basedOn. For a skill from a non-library source, which has no versions, basedOn is the full 40-character commit SHA the fork copied.
Excluding or forking a required skill fails validation and names the library that requires it. To stop using a required skill, stop using the source.
When another installed skill calls a skill you exclude without a replacement, syllabus project sync warns that the skill it calls isn’t installed. With a replacement, the calling skill’s installed copy lists your skill instead in its “Skills this skill uses” line.
You can also exclude a rule that an installed skill cites, such as one outside your rule include. The skill’s installed copy then says the rule is excluded by this repository, with your reason.
Rename a skill
Section titled “Rename a skill”Agents find skills by their install name, the name in SKILL.md, so two installed skills can’t share one. When two sources ship skills with the same name, rename one of them:
sources: fabrica: repository: https://github.com/fabricahq/.syllabus.git skills: include: [skills/review-change] rename: skills/review-change: fabrica-reviewThe installed copy’s name becomes fabrica-review, and it’s installed in <target>/fabrica-review/. The skill’s ID doesn’t change, so configuration, provenance, and update previews still call it fabrica:skills/review-change. Each key must be a skill this source installs, and each new name follows the name grammar.
Syllabus doesn’t rewrite the old name where skill text mentions it, such as in a skill that tells the agent to use review-change. Every sync, update, and build that applies a rename prints the same warning:
Warning: fabrica:skills/review-change is installed as fabrica-review. Mentions of review-change in skill text aren't rewritten; check the skills that call it by that name.When two installed skills still have the same install name, from any sources or your authored skills, sync fails with skill-name-clash, naming both, and writes nothing. Rename or exclude one of them. See Who owns the target folders.
Declare the skills a skill calls
Section titled “Declare the skills a skill calls”A skill can call other skills without listing them in syllabus-skills-used, especially one from a non-library source, whose skills rarely have that metadata. Declare those calls in the source’s skills.uses:
skills: uses: skills/architect: [skills/how]Each key is a skill ID the source installs, and each value lists skill IDs in the same repository. Every ID must exist there. uses adds to what the skill declares itself; it can’t remove a call the skill declares. Syllabus installs the listed skills alongside the skill that calls them, and the installed copy’s “Skills this skill uses” line includes them. Calls can’t form a cycle. Syllabus doesn’t look for calls a skill doesn’t declare: syllabus-skills-used and uses are the only ways it learns of them.
A source’s ref names where to take it from. Each project resolves the ref to a commit when it runs syllabus project update, records that commit in the source’s vendor snapshot, and keeps it on every syllabus project sync:
ref | Sync takes | Update moves to |
|---|---|---|
| (none) | The recorded library release. | The newest library release. |
A branch, such as main | The recorded commit. | The branch’s newest commit. |
A tag, such as release/5 or v1.2 | The recorded commit. | The commit the tag names now, warning when the tag moved since the last update. |
| A full 40-character commit SHA | That commit. | Nowhere; it never moves. |
When a bare name is both a branch and a tag, sync and update fail with ambiguous-ref; write refs/heads/<name> or refs/tags/<name> to say which one you mean. Abbreviated SHAs aren’t accepted.
Sources have no declared type. Syllabus decides when it fetches a source:
- A source whose repository has a manifest is a library. It publishes skill levels, and versioned rules and skills once it has library releases. A library without
release/<number>tags must have aref. - A source without a manifest is a non-library source, such as a third party’s skill collection. Every skill in it is offered, it has no rules or versions, and it must have a
ref, because it has no library releases to follow.rulesis rejected on it.
All of a source’s skills come from its one recorded revision, so skills that call each other always come from the same commit. Skills have no pins. To hold a skill back, exclude or fork it, or set the source’s ref, which holds everything from that source. When a source’s repository gains or loses its manifest, so that the source’s fields no longer fit it, syllabus project update fails and names the fields to change.
Take one revision
Section titled “Take one revision”Taking a library at a revision other than a library release, such as a branch with unreleased changes, opts that source out of versions for what changed: rules and skills whose files match a published version record that version, and the rest record null, have no version to cite, and update previews list the files that changed but no summaries of the changes. syllabus project sync and syllabus project update warn about such a source, naming its unreleased rules and skills, and the generated library summary in generated/libraries/<source-name>/README.md says so. syllabus project check still passes.
A source can use rules.pins or ref, not both.
Pin a rule
Section titled “Pin a rule”rules: pins: - id: practices/testing/verify-retry-limits version: "1.3.0" reason: Waiting on the author's response to acme/.syllabus#45.| Field | Meaning |
|---|---|
id | Required. One rule ID the source includes. Prefixes aren’t accepted. |
version | Required. An exact published version of the rule, such as "1.3.0". Quote it so YAML reads it as text. |
reason | Required non-blank text explaining why the rule stays at this version. syllabus project update shows it next to any newer version, so the decision keeps its context. |
A pin holds the rule at exactly that version:
syllabus project updatenever moves a pinned rule. Its preview lists the pin, the newest available version, and your reason.- When you add or change a pin,
syllabus project syncmoves the rule to the pinned version, up or down, when the source’s recorded library release or an earlier one published it. Sync never moves the source, so a pin to a version published after the recorded library release fails and namessyllabus project update SOURCE, which takes it. - Removing a pin doesn’t move the rule; the next
syllabus project updateoffers its newest version.
To hold a rule at the version you have, pin it to the version recorded in the source’s _source.json, which also appears in the rule’s generated file. syllabus project update --keep writes that pin for you. Skills can’t be pinned; see Refs.
A pinned rule that its library retires stays at its version, and update reports the retirement. To keep a rule the library is retiring, pin it before or during the update that retires it.
Skill targets
Section titled “Skill targets”skillTargets says where installed copies of skills go:
| Value | Folder | Read by |
|---|---|---|
claude | .claude/skills/ at the repository root | Claude Code |
agents | .agents/skills/ at the repository root | Codex, Cursor, and other agents that read the shared folder |
schemaVersion: 2skillTargets: [claude, agents]syllabus project init writes [claude, agents]; --skill-targets claude, agents, or none changes it. Each value can appear once.
skillTargets: [] is valid, and so is leaving the field out. With no targets, Syllabus still records every skill the repository includes, required skills too, lists them in generated/SKILLS.md, and checks them, but writes no installed copies, and sync warns that it installed nothing. Use it to record what your sources require before you choose agent folders.
Each installed skill gets a folder <target>/<install-name>/. Syllabus writes and removes only the skill folders it installed, and leaves every other folder in the target alone, such as a skill another tool installed. Syllabus never writes to your home directory. See Who owns the target folders.
AGENTS.md section
Section titled “AGENTS.md section”By default, project commands keep a section in the repository’s AGENTS.md that tells agents to read the project’s rules and skills; see Where agents start. To manage your agent instructions yourself, turn it off:
schemaVersion: 2manageAgentsFile: falsesources: {}Commands then neither write nor check AGENTS.md. They don’t remove a section they wrote earlier: delete it yourself, along with its markers, and tell your agent to read .syllabus/generated/RULES.md in your own words.
Library manifest
Section titled “Library manifest”The library section makes a repository a library. It publishes the repository’s authored rules, rule groups, skills, and assets, and sets the level of each skill it offers:
schemaVersion: 2sources: mattpocock: repository: https://github.com/mattpocock/skills.git ref: mainlibrary: license: spdxExpression: MIT file: LICENSE.md notices: [] skills: required: [skills/ship-service] recommended: - skills/build-feature - mattpocock:skills/engineering/to-spec offered: - mattpocock:skills/productivity/grilling| Field | Meaning |
|---|---|
library.license | Optional. The terms that cover everything the library publishes. See License metadata. |
library.skills.required | Skills every project that uses the library installs. |
library.skills.recommended | Skills a project installs when it includes recommended. |
library.skills.offered | Skills a project installs when it names them or includes "*". |
An empty library: {} makes a repository a library with no levels and no declared license. Each level is an optional list. Each entry is either an authored skill’s ID, such as skills/ship-service, or a borrowed skill, <source>:<skill-id>, where <source> names an entry in this repository’s own sources. A skill can appear in one level only. An authored skill that no level lists is offered.
syllabus library check validates the manifest, and fails when two listed skills, authored or borrowed, have the same install name, so projects never inherit a clash from one library. See Library format.
The manifest replaces the separate rule-library.yaml that earlier versions used. A repository with a rule-library.yaml fails to load; see No backward compatibility.
Borrowed skills
Section titled “Borrowed skills”A library can list skills from another repository in its levels, such as a third party’s skill it wants its projects to use. The repository it takes them from is a borrowed source: an ordinary entry in the library’s own sources, with the ref the library tracks. A library borrows skills only; rules in its sources are for its own use, and it never publishes them.
- Every borrowed skill is listed. A skill from a borrowed source reaches projects only when a level lists it.
- Files come from the original repository. A skill’s identity is its repository plus its path. Projects fetch a borrowed skill’s files from the borrowed source, not from the library, and provenance records which library required, recommended, or offered it.
- Refs resolve per project. A library release doesn’t lock a borrowed source’s
ref. Each project resolves it when it runssyllabus project updateand records the commit in the library source’s_source.json, soref: maingives each project the newest commit at its own update, without a new library release.syllabus project synckeeps the recorded commit. - A project can override the ref. When a project declares a source with the same repository as a borrowed source, its own
refdecides which commit the borrowed skills come from. Repository identity decides the match, not the source name; see Repository addresses.
The library repository is a project too: it installs the required skills of the sources it borrows from, as any project would, and whatever it includes from them for its own use.
Repository addresses
Section titled “Repository addresses”Use a complete Git address so the host is explicit:
repository: https://gitlab.com/my-team/engineering/rules.gitSupported forms include:
https://github.com/my-team/rules.githttps://gitlab.com/my-team/engineering/rules.gitssh://git@git.example.org:2222/srv/rules.gitgit@git.example.org:engineering/rules.gitgit@git.example.org:/srv/rules.gitNested GitLab namespaces, private hosts, and explicit ports are supported.
The .git suffix is optional. Git uses the caller’s credentials; do not embed HTTPS credentials or SSH passwords in configuration.
SSH usernames are allowed.
Repository addresses do not accept query strings, fragments, git:: prefixes, getter options, or //subdirectory selection.
Local paths, file:, unauthenticated git:, plain HTTP, and remote-helper protocols are outside this format.
The owner/name shorthand isn’t accepted; use https://github.com/owner/name.git instead.
Syllabus preserves the supplied address in provenance and requires the snapshot to match it exactly.
Two addresses name the same repository when they match after normalizing host spelling, standard GitHub.com and GitLab.com transport aliases, and optional .git suffixes. This decides duplicate sources, and which project source overrides a borrowed source’s ref.
GitHub path matching ignores case; generic repository paths and GitLab paths retain case.
Other hosts retain their transport, username, port, and path distinctions.
For example, git@host:rules.git is home-relative, while ssh://git@host/rules.git is absolute. Syllabus does not equate them.
Validation rejects ambiguous paths, including dot segments, encoded separators in URLs, malformed URI escapes, raw whitespace, and backslashes. SCP paths are literal Git paths, so percent signs in that form are not URI escapes. Syntax validation does not fetch or authenticate a repository.
Generated source links use pinned GitHub.com or GitLab.com URLs for recognized standard endpoints.
For other hosts, they point to the retained source file under vendor/<source>/.
If a relative document or image is missing from that snapshot, generation fails with instructions to retain it or supply an explicit URL.
Syllabus does not infer a host’s web interface from its name. See How sources work.
Source names and IDs
Section titled “Source names and IDs”Choose stable source names such as fabrica or acme.
Names must match [a-z][a-z0-9-]*. techs and practices are reserved, because authored rules use those names in generated/rules/.
Declare each repository once.
Inside a source’s configuration, rule and skill IDs are relative to that source, without its name. Everywhere else, in generated files, provenance, review findings, and commands such as syllabus project update fabrica:skills/build-feature, an included rule or skill has a project ID that starts with its source name:
fabrica:practices/testing/verify-retry-limitsacme:practices/testing/verify-retry-limitsfabrica:skills/build-featurefabrica:mattpocock:skills/engineering/to-specpractices/testing/test-project-contractsskills/fix-bug- A rule ID is the rule’s path in its repository’s
rules/folder, without.md. - A skill ID is the skill folder’s path:
skills/<name>for a library’s skills, and the folder’s path from the repository root for a non-library source’s, such asskills/engineering/to-spec. - A borrowed skill’s project ID adds the borrowed source’s name after the library’s, as the manifest lists it. When the project declares the borrowed repository as its own source, the skill’s project ID uses that source’s name instead.
- Authored rules and skills have no source name.
The source name keeps identical IDs from different sources distinct. Renaming a source changes its project IDs and any external references to them. Replacing a repository under an existing source name also requires reviewing its exclude, pins, uses, and rename entries.
The installed copy of a skill goes in a folder named only by its install name, because agents find skills by name. See Rename a skill.
Choose versions
Section titled “Choose versions”Each rule and skill in a library has its own version. A project takes each source from one library release or commit, its lock, and moves it only when someone updates:
vendor/<source-name>/_source.jsonrecords the library release or commit, and the exact version of every included rule and skill.syllabus project syncrestores exactly that, so every checkout has the same content.syllabus project updatepreviews newer versions, new rules and skills, level changes, and retirements, and applies them after you confirm.
syllabus project sync never moves a source. A rule or skill you newly include comes from the recorded library release or commit. When it isn’t there, such as a skill the library published after your last update, sync fails and names the command that moves the source, syllabus project update SOURCE.
A project chooses rule versions one by one, with pins, but not skill versions. All of a source’s skills come from its one recorded revision, and move together when it moves. A skill’s version still says what changed, in release notes, generated/SKILLS.md, the installed copy’s marker line, provenance, and the update preview.
Where each rule’s files come from
Section titled “Where each rule’s files come from”Each rule’s Markdown file and asset directory come from the library release that published its version. Library-wide files, such as rule group metadata, shared assets, the manifest, and license files, and every skill’s whole folder come from the source’s one recorded library release, or from the revision your ref names. That library release is never older than the one that published any included rule version. When it no longer has the metadata of an included rule’s rule group, such as the rule group of a retired rule you pinned, that rule group’s metadata comes from the newest library release among its included rule versions that still has it.
Offline syllabus project build, syllabus project check, and ordinary agent work use the recorded versions without contacting the repository.
Rule groups
Section titled “Rule groups”Rules from the same rule group ID combine into one generated rule group, whatever source supplies them.
Including practices/testing/* from two sources combines both sets of rules into one effective testing rule group, with a rule group page and individual resolved rule files.
Source order never establishes precedence.
Every valid authored rule in rules/ joins its rule group, and needs no configuration entry.
An authored rule with the same ID as an included rule doesn’t replace it; name it in an exclusion’s replacedBy to do that.
An authored rule that an exclusion names as replacedBy appears once under its own ID; the excluded rule is removed from active output.
The complete authored definition supplies the metadata, guidance, attribution, and assets. Configuration and provenance retain the replacement relationship.
An authored _group.yaml defines a rule group, including an empty one, without any configuration entry.
If authored metadata exists for an included rule group, its complete description and reading cues take precedence for discovery.
Otherwise, descriptions from every contributing library remain source-labeled.
Provenance retains all rule group metadata and identifies the sources supplying the effective discovery guidance.
Authored rules without either authored or included rule group metadata are errors, with the missing _group.yaml path in the diagnostic. When a sync or update removes the last source supplying an authored rule’s rule group, it writes that rule group’s last vendored metadata to rules/<group-id>/_group.yaml instead of failing; see Keep the rule group of an authored rule.
The generated index shows rule group names, applicability guidance, and explicit Open group links. Without authored metadata, guidance from multiple libraries remains labeled by source. Syllabus does not silently choose one library’s description over another’s.
Conflicting rules
Section titled “Conflicting rules”Source-qualified IDs prevent naming collisions, but distinct rules can still require incompatible behavior in the same situation. Both remain active unless the repository explicitly excludes or replaces a rule under its owning source. Syllabus does not infer priority from source order or interpret prose to resolve contradictions.
See Resolve conflicting rules for examples, an agent review prompt, and ways to resolve competing instructions.
Skill precedence
Section titled “Skill precedence”Skill decisions layer in this order, each overriding the ones before it: a library’s levels, then an org library’s, then the project’s configuration, then each person’s personal skills. Required skills are a floor: the project can add, rename, and replace around them, but can’t remove them.
A personal skill with the same name as a skill the repository installs wins in some agents, even over a required skill. Syllabus can’t prevent that, and doesn’t write to your home directory. It warns instead; see Personal skills with the same name.
No backward compatibility
Section titled “No backward compatibility”Syllabus reads only version 2 configuration. A version 1 configuration, or a repository with a rule-library.yaml, fails to load, with a message that shows the version 2 shape:
Error: .syllabus/config.yaml uses schemaVersion 1, which this version of Syllabus doesn't read. Rewrite it in the version 2 shape, for example:
schemaVersion: 2 skillTargets: [claude, agents] sources: fabrica: repository: https://github.com/fabricahq/public-rules.git rules: include: [practices/testing/*] exclude: - id: practices/testing/avoid-snapshot-tests reason: ...
Move authored rules from local/ to rules/, and authored skills to skills/. See https://syllabus.fabricahq.com/reference/configuration/There’s no upgrade command. Rewrite the file by hand:
| Version 1 | Version 2 |
|---|---|
groups: [practices/testing] | rules: {include: [practices/testing/*]} |
groups: "*" | rules: {include: ["*"]} |
rules: [techs/go/wrap-errors] | Add the IDs to rules.include. |
exclude and pins maps keyed by rule ID | rules.exclude and rules.pins lists, each entry with an id. |
replacedBy: local/techs/go/x.md | replacedBy: techs/go/x, the authored rule’s ID. |
.syllabus/local/<group-id>/ | .syllabus/rules/<group-id>/ |
rule-library.yaml and root-level techs/, practices/, and assets/ | A library section in .syllabus/config.yaml, and .syllabus/rules/ and .syllabus/assets/. |
Version boundaries
Section titled “Version boundaries”schemaVersion describes this configuration.
The caller-supplied toolVersion identifies the tool that generated the output.
Each source’s pins, and its ref when present, state which versions the project wants; every other rule and skill follows the source’s lock, which only syllabus project update moves.
Vendored provenance records each included rule’s and skill’s version, library release, and commit, or a non-library source’s commit, used by offline commands. It is output Syllabus owns, not a second version the project chooses.
See Library format for library contents and Include rules for examples of exceptions.