Skip to content

About

Spec Kit extension: inject cross-repo decisions, contracts, and conventions into your spec-kit workflow

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

ย 

History

137 Commits

Folders and files

Repository files navigation

๐Ÿ“š Shared Knowledge

A spec-kit extension that injects architectural decisions, API contracts, and shared conventions from other Git repositories into your spec-kit workflow.

License: MIT Spec Kit Status

๐Ÿ“– Overview

When working in a microservices or multi-repo environment, architectural decisions and API contracts are scattered across repositories. This extension lets you declare which repositories are "knowledge sources" for your project. During /speckit-specify, /speckit-clarify, /speckit-plan, and /speckit-tasks, the assistant automatically loads and surfaces relevant knowledge from those sources โ€” so the generated spec, plan, and tasks reflect the real contracts and decisions your team has already made.

Key features:

  • ๐Ÿ™‹ Explicit opt-in: each project declares its own knowledge sources
  • ๐ŸŒฟ Git-native: clones repositories with sparse checkout (only the paths you need)
  • โœˆ๏ธ Offline-friendly: cached knowledge is used when sources are unreachable
  • ๐Ÿ“‚ Path-filtered: scope reads to specs/, docs/decisions/, or any subdirectory
  • โš ๏ธ Conflict-aware: duplicate paths across sources are flagged, both versions surfaced
  • ๐Ÿ“Œ Revision-pinned: lock a source to a branch, tag, or full commit SHA
  • โณ Cache-aware: skip the network entirely while the cache is still current
  • ๐Ÿ“ Budget-bounded: cap how much the agent is told to read โ€” nothing is withheld silently
  • ๐Ÿšฆ Lifecycle-managed: remove, disable, or re-enable a source without hand-editing YAML

๐Ÿ“‹ Prerequisites

  • git >= 2.25 (sparse-checkout support required)
  • timeout, gtimeout, or perl, to bound network calls. Stock macOS ships perl, which is enough; with none of the three, calls run unbounded and sync warns once.
  • spec-kit >=0.15.2
  • Platforms: macOS and Linux; Windows through WSL or Git Bash

๐Ÿ“ฆ Installation

๐ŸŒ Published release

specify extension search finds extensions in spec-kit's community catalog, but that catalog is searchable, not installable, by default. Install the published release from its archive:

specify extension add knowledge --from https://github.com/rnoap/spec-kit-shared-knowledge/archive/refs/tags/v1.10.2.zip

spec-kit first shows an Untrusted Source prompt naming the URL. Confirm it to install.

A team that wants no prompt can list the extension in a catalog it controls and marks install-allowed. specify extension add knowledge then installs from that catalog without asking.

๐Ÿ’ป Local / Development Install

Install directly from a local checkout โ€” the path is the positional argument:

cd /path/to/your/spec-kit-project
specify extension add /path/to/spec-kit-shared-knowledge --dev

This copies the five command files, the manifest, and config-template.yml into .specify/extensions/knowledge/, scaffolds knowledge-config.yml, registers the extension, and auto-registers the before_specify, before_clarify, before_plan, and before_tasks hooks. The first /speckit-knowledge-configure adds the cache entries to your .gitignore for you โ€” see .gitignore.

Then reload your editor / AI agent so it picks up the new commands.

๐Ÿš€ Quick Start

# 1a. Add a knowledge source from a REMOTE repository (single folder filter)
/speckit-knowledge-configure https://github.com/your-org/payment-service specs/

# 1b. โ€ฆ or from a LOCAL repository on your machine
/speckit-knowledge-configure ~/repos/payment-service specs/

# 1c. โ€ฆ or with NO filter (indexes every .md file in the repo, minus the default exclusions)
/speckit-knowledge-configure [email protected]:your-org/architecture-decisions.git

# 1d. โ€ฆ or scoped to MULTIPLE folders
/speckit-knowledge-configure ~/repos/shared-contracts specs/ docs/decisions/

# 2. Sync (fetch & cache)
/speckit-knowledge-sync

# 3. Use โ€” run /speckit-specify (or clarify, plan, tasks), accept the sync prompt, and cross-repo context is injected

๐Ÿงฐ Commands

The examples use the hyphenated form, such as /speckit-knowledge-sync. That is what agents that install commands as skills show, including GitHub Copilot and Claude Code. Agents that install slash commands show the dot form listed in the table below, such as /speckit.knowledge.sync; Codex shows $speckit-knowledge-sync, and Kimi /skill:speckit-knowledge-sync. spec-kit's own commands follow the same pattern: /speckit-specify or /speckit.specify.

Command Dot form What it does
๐Ÿ”ง /speckit-knowledge-configure /speckit.knowledge.configure Initialize or edit the knowledge source configuration
๐Ÿ”„ /speckit-knowledge-sync /speckit.knowledge.sync Refresh the local cache for all configured, enabled sources
๐Ÿ” /speckit-knowledge-search /speckit.knowledge.search Browse and search the knowledge corpus
๐Ÿ“Š /speckit-knowledge-status /speckit.knowledge.status Show reachability, revision, last sync, item count, budget, and cache age
๐Ÿ”Œ /speckit-knowledge-remove /speckit.knowledge.remove Remove, disable, or re-enable a configured source

๐Ÿ”ง /speckit-knowledge-configure [url-or-path] [--revision <rev>] [--label <label>] [path_filter ...]

Initialize or edit the knowledge source configuration for the current project. Accepts:

  • A remote Git URL โ€” HTTPS (https://github.com/your-org/your-repo) or SSH ([email protected]:your-org/your-repo).
  • A local filesystem path to a Git repository โ€” use this when the repo is already cloned on your machine and you want to avoid network roundtrips, or when it lives on a private network. Both absolute paths and ~-prefixed paths are supported (the tilde is expanded to $HOME).
  • An optional revision โ€” a branch, tag, or full commit SHA. See Pinning a revision.
  • An optional label โ€” choose the name shown for the source. If omitted, the command derives it from the URL or local path.
  • Zero or more path filters after the URL/path. With zero filters every .md file in the repo is indexed, except root-level dot-directories (.specify/, .github/, โ€ฆ) and AGENTS.md, CLAUDE.md, GEMINI.md. With one or more filters, indexing is restricted to the .md files in those folders only.

Examples:

# Remote URL, single folder filter
/speckit-knowledge-configure https://github.com/your-org/payment-service specs/

# Choose a label, with no folder filter
/speckit-knowledge-configure https://github.com/your-org/payment-service --label payments-main

# Choose a label and multiple folder filters
/speckit-knowledge-configure https://github.com/your-org/payment-service --label payments-v2 specs/ docs/decisions/

# Local absolute path, single folder filter
/speckit-knowledge-configure /Users/devuser/repos/payment-service specs/

# Local path containing a space: quote it
/speckit-knowledge-configure '~/My Repos/kb' specs/

# Local path with tilde, NO filter (indexes every .md in the repo, minus the default exclusions)
/speckit-knowledge-configure ~/repos/architecture-decisions

# Local path, MULTIPLE folder filters
/speckit-knowledge-configure ~/repos/shared-contracts specs/ docs/decisions/

# Pinned to a tag
/speckit-knowledge-configure https://github.com/your-org/payments --revision v2.4.1 specs/

# Use the derived label by omitting the optional label
/speckit-knowledge-configure https://github.com/your-org/architecture-decisions specs/

# Same, using the @ shorthand (HTTPS and local paths only โ€” not SSH)
/speckit-knowledge-configure https://github.com/your-org/[email protected] specs/

Quoting: arguments are split at spaces. A URL or path without spaces needs no quotes; quote a local path that contains one, with single or double quotes:

You type url path_filter
~/repos/kb specs/ ~/repos/kb specs/
'~/My Repos/kb' specs/ ~/My Repos/kb specs/
~/My Repos/kb specs/ ~/My, which does not exist, so nothing is written Repos/kb and specs/

Output:

โœ… knowledge-config.yml updated.
โœ… .gitignore updated with cache exclusion entries.

Configured sources:
  1. payment-service     โ†’  https://github.com/your-org/payment-service  (path: specs/)
  2. architecture-decisions โ†’ ~/repos/architecture-decisions             (path: all .md files)
  3. shared-contracts    โ†’  ~/repos/shared-contracts                     (paths: specs/, docs/decisions/)

Flags:

  • --verbose โ€” print full YAML after write
  • --label <label> โ€” optional source name. It may appear before or after the path filters.

๐Ÿ”„ /speckit-knowledge-sync [--force]

Refresh the local cache for all configured, enabled knowledge sources.

๐Ÿ”„ Syncing cross-repo knowledge sources...

  payment-service    โœ… fresh    12 items  (synced 2026-06-11T14:00:00Z)
  payments-v2        โญ๏ธ  current  12 items  (cached 12m ago; policy 4h โ€” no network)

โœ… Knowledge index updated: 24 items from 2 sources.
   โ†’ .specify/extensions/knowledge/knowledge-index.md

Flags:

  • --verbose โ€” list all files loaded and items written to index
  • --force โ€” ignore the cache freshness policy and fetch every source
  • --no-context-output โ€” suppress the trailing context block for the AI agent (diagnostic use only)

๐Ÿ” /speckit-knowledge-search <query>

Browse and search the knowledge corpus without triggering a full spec workflow.

๐Ÿ” Search: "payment session"

Found 2 items across 1 source:

  ๐Ÿ“„ payment-service โ€บ specs/events/payment-completed.md
     Tags: specs, events, payment-completed
     Excerpt: "Payment completed event fired after successful charge..."

Flags: --source <label>, --tag <tag>, --verbose

๐Ÿ“Š /speckit-knowledge-status

Display current state of all configured sources.

๐Ÿ“Š Shared Knowledge Status

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Source           โ”‚ Reachability โ”‚ Revision โ”‚ Status โ”‚ Items โ”‚ Cache Age  โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ payment-service  โ”‚ โœ… reachable โ”‚ default  โ”‚ fresh  โ”‚ 12    โ”‚ 14 min     โ”‚
โ”‚ payments-v2      โ”‚ โœ… reachable โ”‚ v2.4.1   โ”‚ fresh  โ”‚ 12    โ”‚ 3d         โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Freshness policy: payments-v2 7d (per-source) ยท others 4h (project)

With a context budget configured, Items shows indexed-of-total and an extra Budget column names the limit that produced each number.

Flags: --verbose โ€” list all cached file paths per source

๐Ÿ”Œ /speckit-knowledge-remove <label> [--disable | --enable]

Remove, disable, or re-enable a configured source. Named for its destructive mode, but it owns the whole activation lifecycle โ€” there is deliberately no second command that also writes enabled.

# Delete the entry AND purge its cache
/speckit-knowledge-remove payments-v2

# Keep the entry and the cache; just stop consuming it
/speckit-knowledge-remove payments-v2 --disable

# Bring it back โ€” no re-download, because the cache was kept
/speckit-knowledge-remove payments-v2 --enable

# No identifier: pick from a list of configured sources
/speckit-knowledge-remove

Takes a label, which is unique by construction. A URL is also accepted, but only when it resolves to exactly one source โ€” with revision pinning a URL can match several, and the command lists the candidates rather than guessing:

โŒ "https://github.com/org/payments" matches 2 configured sources:
     payments-v2   (revision: v2.4.1)
     payments-main (revision: main)
   Re-run with a label to disambiguate. Nothing was changed.

Flags: --disable, --enable, --verbose

๐Ÿšฆ Source lifecycle

Stop, pause, or resume a source without editing YAML:

You want to Use Entry Cache
๐Ÿ—‘๏ธ Stop consuming it permanently remove <label> deleted purged
โธ๏ธ Pause it temporarily remove <label> --disable kept, enabled: false kept
โ–ถ๏ธ Bring a paused source back remove <label> --enable kept, enabled: true reused

๐Ÿ’ก Prefer --disable over remove for a pause. The cache is retained, so re-enabling costs no download at all. Removal purges immediately rather than deferring to a cleanup step โ€” "remove" that leaves the bytes behind is the more surprising reading.

When the last enabled source goes away, sync reports the project as unconfigured and deletes the knowledge index. A stale index would let an agent keep citing knowledge the project no longer declares โ€” a silent failure that looks like success.

๐Ÿ“Œ Pinning a revision

Each source may pin a revision โ€” a branch, tag, or full commit SHA:

sources:
  - url: https://github.com/org/payments
    label: payments-v2
    revision: v2.4.1
    path_filter: specs/

Omit it and the source tracks the remote's default revision.

  • Two revisions of one repository can be configured side by side. They hold separate caches and cannot contaminate each other.
  • Because a URL then no longer identifies one source, every source carries a unique label, enforced when it is added. The label is what remove takes.
  • Overlapping file paths between two revisions of the same repository are not reported as conflicts. Conflicts are reported only between sources whose repository identity differs โ€” identity ignores the access protocol, so HTTPS and SSH for the same repo are the same repo.
  • Abbreviated SHAs are not supported. A 7-character prefix is not fetchable and is not stable โ€” one that is unique today can become ambiguous as the repo grows.
  • SSH URLs already contain @, so pass the revision with --revision rather than the <url>@<rev> shorthand.

โš ๏ธ Known limitation. A source configured as a local path is not identified with the remote it was cloned from. If you configure both ~/repos/payments and https://github.com/org/payments, overlapping paths between them are reported as conflicts. Reading the local clone's origin would fix this but adds a failure mode and a trust question to a purely advisory report, so it is deliberately not done.

๐Ÿ‘ฅ Reading a teammate's unmerged spec

A teammate's spec can be a source before it is merged, as long as its branch is pushed. Add the repository you share, pin the teammate's branch, and filter to the spec's folder:

/speckit-knowledge-configure https://github.com/your-org/your-repo --revision 012-order-tracking specs/012-order-tracking/
  • Filter to the spec's folder. The branch also carries everything already on main; without a filter you index your own specs a second time.
  • Use the remote URL. A local path can only check out branches that exist locally in that clone.
  • A branch moves. Every refresh fetches its latest commit. To keep the version you reviewed, pin its full commit SHA instead.
  • Remove the source when either branch merges. After the teammate's branch merges, the spec reaches you through main. Merging yours with the source still configured makes every teammate sync a temporary branch. Run /speckit-knowledge-remove <label>.
  • A deleted branch is not an error. Sync keeps serving the last cached copy and reports the source as cached.

โณ Cache freshness

Set max_cache_age and a sync will skip the network entirely when the cached content is still current:

max_cache_age: 4h        # project-wide

sources:
  - url: https://github.com/org/payments
    label: payments-v2
    max_cache_age: 7d    # overrides the project value for this source

Format is <N><unit> with unit m, h, or d โ€” 30m, 4h, 7d.

This is what makes the four automatic hooks affordable. Without a policy, one feature cycle (specify โ†’ clarify โ†’ plan โ†’ tasks) refetches every source four times. With 4h set and the cycle finished inside that window, it fetches once.

  • Omitted is the default, and means no policy: every sync fetches.
  • A skipped source is reported as โญ๏ธ current, distinct from fresh, so you can see no network access happened.
  • --force ignores the policy. It is unreachable from an automatic trigger โ€” the hook entries declare no arguments โ€” so hook-driven syncs always respect the policy.
  • It is a hint, not an expiry. An over-age cache is still served when its source cannot be reached. Setting a policy never leaves you with less knowledge than you had without one.

๐Ÿ“ Context budget

Every sync tells the agent to read the index in full and open every file it references. That instruction has no upper bound, and the corpus grows with your team. Two optional ceilings give it one:

max_items: 120        # project-wide
max_bytes: 1mb        # project-wide

sources:
  - url: https://github.com/org/big-docs
    label: big-docs
    max_items: 40     # sub-ceiling for this source

max_items is a whole number โ‰ฅ 1. max_bytes is <N>kb or <N>mb in binary units. Both are optional and independent โ€” set either, both, or neither.

A per-source ceiling is a sub-ceiling, not an override. It can only lower what that source contributes, never raise it. This is deliberately unlike max_cache_age, which sits in the same two positions in the file but whose per-source value replaces the project value. A per-source budget above the project ceiling is clamped down to it and the clamp reported โ€” it never invalidates the source.

๐Ÿงฎ What gets kept, and how you can predict it

The rule is fixed, owned by the extension, and influenced by no configuration value โ€” so you can work out your own index on paper. Per dimension:

  1. share = โŒŠceiling รท number of sources with itemsโŒ‹
  2. Every source needing no more than its share is satisfied in full, and releases the remainder to the others. Repeat from 1 with what is left.
  3. When a pass satisfies nobody, everyone left takes share.
  4. Any remainder goes one item each, in ascending label order.

Within a source, items are taken in ascending path order โ€” not smallest-first. Smallest-first would fit more files, but adding one large document would silently change which unrelated small ones survive, and you could no longer predict your own corpus.

โœ๏ธ Worked example. Ceiling 120 items; four sources holding 312 / 55 / 88 / 12. Share is โŒŠ120/4โŒ‹ = 30; the 12-item source is satisfied and releases 18; โŒŠ108/3โŒ‹ = 36 and nobody else fits, so the other three take 36 each. 36 + 36 + 36 + 12 = 120. A flat quarter-share each would have injected only 102 and stranded 18 โ€” releasing unused share is what fills the ceiling.

๐Ÿ“ฃ Nothing is withheld silently

  big-docs           โœ… fresh    36 items
                     โœ‚๏ธ  budget: 36 of 312 items (118kb of 3.4mb) โ€” limit 36 items (share of 120)

โš ๏ธ  Withheld: big-docs โ€บ huge.md (2.4mb) exceeds the 1mb size ceiling on its own;
    excluded without consuming the budget.

โœ… Knowledge index updated: 120 items from 4 sources (347 withheld, 3.5mb).
  • The index header carries the same counts, and marks itself โš ๏ธ Partial.
  • The agent is told the corpus is partial, so it will not present it as complete.
  • --verbose lists every withheld path.
  • /speckit-knowledge-search still finds withheld items. The budget bounds what is injected automatically, not what the project knows โ€” nothing leaves the cache.

Two versions of a conflicting path are kept or dropped together; the budget never picks a winner between two teams' versions of the same file.

๐Ÿ’ก If you set no budget

No default is applied, so nothing is withheld. Once the corpus passes 200 items or 2 mb, sync says so once per run:

โš ๏ธ  This project's knowledge corpus is 340 items / 2.7mb, past the advisory
    threshold of 200 items / 2mb. An agent instructed to read all of it may
    exhaust its context. Consider setting `max_items` or `max_bytes`.

It changes nothing it reports on โ€” same standing as the existing "more than ten sources" warning.

๐Ÿ”’ No flag raises or bypasses the budget. --force overrides cache freshness only. The automatic sync points are exactly where a context overflow does the most damage, so there is no escape hatch reachable from them.

๐Ÿ” Trust model

knowledge-config.yml is committed and shared. That is the point โ€” it declares your team's knowledge sources โ€” but it also means a merged pull request adding one url line causes that location to be fetched on every teammate's machine and every automated environment that later runs a sync. Including via the four automatic hooks, which the reviewer who approved the change may never invoke themselves.

This section states what that grants, and what it does not.

๐Ÿšซ What does NOT happen

Fetched content is read as data. It is never executed.

  • No build step, script, or repository hook from a source is ever run.
  • No configuration value and no fetched file name is ever run as a command.
  • Clones use --no-checkout and --filter=blob:none; only .md files under your path_filter are read.
  • Nothing from a source is written outside .specify/extensions/knowledge/cache/<slug>/.

โœ… What the extension defends against

Defense Covers Does not cover
Values beginning with - are rejected Argument injection into git โ€” a revision of --upload-pack=<cmd> would be remote code execution A legitimately shaped value pointing somewhere hostile
-- before every config-derived git operand The same, if validation is ever bypassed As above
Validation runs on read, not just write Values arriving by hand-edit or by PR Values that are valid but unwanted
url and path_filter accept only ASCII letters, digits and . _ ~ : / @ % + -, plus spaces in a local path A merged configuration change running commands on teammates' machines A well-formed value pointing somewhere hostile
Every value reaches the shell inside single quotes, and fetched file names only through shell variables The same, if validation is ever bypassed, and hostile file names in a source As above
--no-checkout + --filter=blob:none Fetching a working tree wholesale The subsequent checkout, which does write the filtered files
Every network call is time-bounded: 10 s, 30 s for a full-history fetch, 5 s in status A hung or tarpitting host A fast host serving hostile content
path_filter Corpus size and blast radius Anything inside the filtered paths
Symbolic links are never followed: clones write them as plain files, and only regular files git does not record as links are indexed A source pointing the agent at a file outside the cache, such as ~/.ssh/id_rsa or the project's .env Hostile content in an ordinary .md file
Hooks are optional: true Unattended fetches โ€” you are prompted A prompt you accept
Manifest SHA-256 integrity check Local cache corruption Content that was hostile when fetched

๐Ÿšจ What it does NOT defend against

Stated plainly, because a trust model that lists only its strengths is worse than none:

  1. Prompt injection. Fetched markdown enters the agent's context uninspected and unsanitized. A source can contain instructions aimed at your agent. There is no reliable general defense and this extension does not attempt one.
  2. Credential exposure. Your local git credential helper decides what to send to a configured host. The extension neither scopes nor filters it. A URL pointing at an attacker-controlled host may be offered credentials.

๐Ÿ‘€ Reviewing a change to knowledge-config.yml

Treat it as a security-relevant change, not a config tweak. Before approving:

  • Is the url a repository your organisation controls, or one you have reason to trust with your credentials and your agent's context?
  • Is it reached over a host you expect? Check for lookalike domains.
  • Is revision pinned to a tag or full SHA, rather than tracking a branch someone else can move under you?
  • Does path_filter scope the read to what is actually needed?
  • Do you understand that this will fetch on your machine the next time you run any spec-kit command with a knowledge hook enabled?

If a source is outside your organisation, prefer a pinned revision and a narrow path_filter, and read what it contains before merging.

๐Ÿ”— Integration with the spec-kit lifecycle

The hooks declared in extension.yml are auto-registered by spec-kit when the extension is installed via specify extension add โ€” no manual edits to .specify/extensions.yml are required. See the spec-kit Extension Development Guide for the underlying mechanism.

Hook Runs before Why
before_specify /speckit-specify Spec drafting reflects current contracts
before_clarify /speckit-clarify Ambiguities resolved against real decisions
before_plan /speckit-plan Planning sees the current architecture
before_tasks /speckit-tasks Task breakdown reflects current contracts

All four are optional, so spec-kit prompts before each sync and you can decline. Set a max_cache_age and an accepted hook skips the network while the cache is still current โ€” with 4h and a feature cycle that fits inside it, you fetch once instead of four times.

The AI agent's knowledge-reading behavior is driven by the Context Output block emitted at the end of every successful or degraded sync (see commands/speckit.knowledge.sync.md ยง "10. Emit Context Output for AI Agents block").

๐Ÿ’ค No-op when not configured: If .specify/extensions/knowledge/knowledge-config.yml does not exist, all commands exit 0 with a "not configured" message. Projects without the extension are completely unaffected.

๐Ÿ’ฌ Ask in plain language

Outside the spec-kit commands, the agent has no reason to look at the knowledge index. The cache is git-ignored, so its file search usually skips it too. So every sync keeps a short section in your project's root AGENTS.md, which agents such as Copilot and Codex read in every chat:

<!-- KNOWLEDGE START -->
## Shared knowledge

For any question about another repository or a knowledge source listed below:

1. Read `.specify/extensions/knowledge/knowledge-index.md` first.
...
Sources:
- `payment-service`
<!-- KNOWLEDGE END -->

Then ask "how does payment-service retry failed charges?" with no command and no file named. The agent reads the index and cites payment-service โ€บ <path>.

  • Sync creates AGENTS.md if needed, adds or refreshes the section, and writes nothing when it is already current. Nothing outside the markers is touched.
  • Remove, --disable and --enable refresh the label list at once, without a sync. The agent uses only the listed sources, so a disabled source stops being cited even though the index still lists it until the next sync.
  • The section is safe to commit. It holds no timestamps or machine paths, so teammates produce the same bytes. On a fresh clone without an index, it tells the agent to suggest a sync.
  • Opt out with agents_md: false in knowledge-config.yml. The next sync removes the section, and AGENTS.md is left alone from then on.

๐Ÿ“‘ Configuration Reference

See config-template.yml for the full annotated configuration schema.

Top-level fields:

  • schema_version โ€” required; exactly "1.1". Any other value stops every command before it uses a source.
  • max_cache_age โ€” optional; project-wide freshness policy (30m, 4h, 7d). See Cache freshness.
  • max_items / max_bytes โ€” optional; project-wide context budget. See Context budget.
  • agents_md โ€” optional; default true. Exactly true or false. false removes the shared knowledge section from AGENTS.md and leaves the file alone; an invalid value leaves AGENTS.md untouched. See Ask in plain language.
  • sources โ€” required; the list of knowledge sources. May be empty.

Key fields per source entry:

  • sources[*].url โ€” required. Only ASCII letters, digits and . _ ~ : / @ % + -. A local path starts with /, ./, ../ or ~/ and may also contain spaces, but no space followed by -. Remote addresses write spaces as %20. Must not begin with -. One of:

    • HTTPS Git URL: https://github.com/your-org/your-repo
    • SSH Git URL: [email protected]:your-org/your-repo
    • SSH URL with a port: ssh://[email protected]:2222/team/kb.git
    • Git+SSH URL: git+ssh://[email protected]/~alice/kb.git
    • Local absolute path to a Git repository: /Users/devuser/repos/your-repo
    • Local tilde path (expanded to $HOME): ~/repos/your-repo
    • Local relative path: ./vendor/kb or ../kb
    • Local path containing spaces: ~/My Repos/kb; pass it to configure as '~/My Repos/kb' specs/ so it stays one argument.
  • sources[*].label โ€” optional; human-readable name used for attribution, and the identifier remove takes. Must be unique and contain no whitespace. Defaults: for remote URLs, <host>/<org>/<repo> derived from the URL; for local paths, the last path component (e.g. ~/repos/payment-service โ†’ payment-service).

  • sources[*].revision โ€” optional; a branch, tag, or full commit SHA. Omitted โ†’ the remote's default revision. See Pinning a revision.

  • sources[*].path_filter โ€” optional folder names. Each entry accepts only ASCII letters, digits and . _ ~ : / @ % + -, with no leading /, ~ or -, no .., no spaces and no wildcards. Three forms:

    • Omitted โ†’ every .md file in the repo is indexed, except those under root-level dot-directories (.specify/, .github/, .wibey/, .claude/, โ€ฆ) and files named AGENTS.md, CLAUDE.md or GEMINI.md. Those hold another project's tool and agent instructions, not shared knowledge. Root dotfiles and nested hidden folders are kept.
    • Single string โ†’ path_filter: specs/ indexes only the .md files under specs/.
    • YAML list โ†’ path_filter: [specs/, docs/decisions/] indexes those two trees and nothing else.

    An explicit filter is honored as written, so path_filter: .github/docs/ indexes that folder despite the default exclusions. Either way, only .md files are cached: the sparse checkout never writes code, images or configuration to disk.

  • sources[*].enabled โ€” optional; default true; set false to skip a source without removing it from the file โ€” or run /speckit-knowledge-remove <label> --disable.

  • sources[*].max_cache_age โ€” optional; replaces the project-wide value for this source.

  • sources[*].max_items / sources[*].max_bytes โ€” optional; a sub-ceiling that can only lower what this source contributes.

Every value is validated each time the file is read, before any shell use. A source with an invalid value is skipped with a message naming its field and first disallowed character; the other sources still sync. Messages show control characters escaped, such as \n, rather than letting them rewrite the terminal.

๐Ÿ™ˆ .gitignore

The /speckit-knowledge-configure command automatically adds the required cache exclusion entries to your project's .gitignore when you first configure a source โ€” no manual step needed.

If you need to add them by hand (e.g. before running configure for the first time):

# knowledge extension cache (local only; do not commit)
.specify/extensions/knowledge/cache/
.specify/extensions/knowledge/knowledge-index.md

The knowledge-config.yml config file should be committed โ€” it declares your team's knowledge sources and is shared across all developers.

๐Ÿฉบ Troubleshooting

๐Ÿ“ก Source unreachable: The command falls back to the existing cache and reports โš ๏ธ cached with the last-sync timestamp and cache age. The command always exits 0.

๐Ÿ’ฅ Corrupted cache: When .manifest.json no longer matches the cached files, the Cache Integrity Check fails. Status shows corrupted, search leaves the source out, and the next sync records it again. A cache directory left without a manifest or without its own .git, by a failed or stopped clone, is removed and cloned again. If the source is unreachable at that moment, it is marked โŒ unreachable.

๐Ÿ”„ First sync after an upgrade: specify extension add recreates the extension's folder and keeps only knowledge-config.yml, so the cache and the index are gone. The next sync rebuilds every source.

โฏ๏ธ A sync that stopped part-way: Run /speckit-knowledge-sync again. Sources already recorded take the warm path, and every source left without a manifest is cloned again.

๐Ÿงพ corrupted right after upgrading from 1.9.1 or earlier: Sync now writes each manifest itself, in one exact layout, so a manifest an agent wrote before fails the check once. The next sync records it again and the row clears.

๐Ÿ”ค File skipped, name not valid UTF-8: JSON cannot hold that name, so sync leaves the file out of the manifest and the index and names it with \xHH escapes. Rename it in the source repository to bring it back.

๐Ÿข More than 10 sources: A soft warning is emitted before the sync loop. The command continues normally โ€” the warning is informational only. Use path_filter to reduce per-source clone size.

๐Ÿค” Context not appearing in spec output: The hooks are optional โ€” check that you accepted the sync prompt. Then run /speckit-knowledge-status to confirm sources are reachable and knowledge-index.md exists. With no enabled sources left, sync deletes the index on purpose.

๐Ÿค Contributing

Contributions are welcome. To propose a change:

  1. ๐Ÿ’ฌ Open an issue describing the bug or enhancement before sending a PR for non-trivial changes
  2. ๐Ÿด Fork the repo and create a feature branch (feat/<short-name> or fix/<short-name>)
  3. ๐Ÿ“ Update CHANGELOG.md under [Unreleased] with your change
  4. ๐Ÿงช Test the change with specify extension add /path/to/spec-kit-shared-knowledge --dev against a real spec-kit project
  5. โœ… Run bash .github/scripts/validate-extension.sh (needs python3 with PyYAML) โ€” CI runs the same checks, plus an install smoke test, on every pull request
  6. ๐Ÿš€ Open a pull request and reference the issue

For larger architectural changes, please file a discussion first. See specs/ for the feature specs that document the current behavior.

๐Ÿ“œ License

MIT ยฉ Raรบl Noa Pedroso

About

Spec Kit extension: inject cross-repo decisions, contracts, and conventions into your spec-kit workflow

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages