Spektacular (Spek) splits configuration across two files: a project's own .spektacular/config.yaml, which locates each member repository, and each member repository's .spektacular/repo.yaml, which describes it and says where its code lives.
A project’s own settings: the coding agent it drives, where it stores
speks, plans, and changelog records, its shared knowledge stores, and the
repositories it registers as members. Every project has exactly one
.spektacular/config.yaml, at the root of the project. The file is
created by spektacular init, missing keys fall back to defaults, and
${VAR} patterns are expanded from the environment when config.yaml
or repo.yaml is read. A complete example, declaring one shared knowledge
store alongside the store each registered repository brings with it:
schema: 4 # settings format version; `migrate` raises itwritten_by: 0.16.0 # the Spektacular version that last wrote this fileskills_version: 0.16.0 # the Spektacular version that installed the agent skills
command: spektacularagent: claudespec_trigger_threshold: moderateepic_split_threshold: moderateauto_commit: "off" # off | workflow | full
debug: enabled: false
spec: provider: file id_method: timestamp config: directory: specs # relative to the folder holding `config.yaml`
plan: provider: file config: directory: plans task_id: provider: uuid # where plan task ids come from
changelog: provider: file config: directory: changelog
epic: provider: file strict_dependencies: false # true refuses to implement past an unmet dependency config: directory: epics # created the first time an epic is written
knowledge: sources: # the project's shared stores only; each - name: team # repository declares its own in repo.yaml provider: file config: location: ${HOME}/work/team-knowledge # or ../../team-knowledge, # relative to this file
design: sources: # where the project's design documents live; - name: api # declared by the project, never by a repository provider: file config: location: ../design/api # relative to this file; may sit outside the project
repos: - name: docs location: ../../docs/.spektacularSixteen top-level keys control the tool from .spektacular/config.yaml:
schema, written_by, skills_version, command, agent,
spec_trigger_threshold, epic_split_threshold, auto_commit, debug,
spec, plan, changelog, epic, knowledge, design, and repos.
schema integer The settings format version. Never edit it by hand; migrate raises it.
A file with no schema is read as the oldest format and needs an
upgrade, as described under Upgrading a project below.
written_by string The Spek version that last saved this file. Informational only: it never triggers an upgrade, so a file written by a different version of the same format is left alone.
skills_version string The Spek version that last installed your agent skills. Only
init and migrate set it, so rewriting the file for any other reason,
registering a repository for example, leaves it untouched. When it
differs from the running Spek, commands stop until you upgrade.
command string spektacularThe CLI command name used in agent-generated documentation. Almost never needs to change, kept configurable so downstream tooling can refer to a different binary name if your team wraps the tool.
agent string spektacular init Which coding agent to drive during the implement workflow. Supported
values: claude (Claude Code), bob, codex, and omp (oh-my-pi). New agents register
via the Agent plugin interface.
On shared projects, each spektacular init <agent> records that agent here.
Migration refreshes only the recorded agent’s files, leaving other agents’
copies behind. After upgrading, run spektacular init once for each agent
to refresh every copy; otherwise omp may list both current and stale skills.
spec_trigger_threshold string moderateHow readily the agent offers to capture an open-ended discussion as a
spek mid-conversation, rather than waiting for you to run /spek-new.
One of strict (only substantial, multi-requirement features),
moderate (default: a clear scoped decision or a feature with more
than one requirement), or lenient (offers readily, including small
fixes). Read live at the moment the agent decides whether to offer, so a
change here takes effect immediately, mid-conversation.
epic_split_threshold string moderateHow readily the agent offers to split a complete spek that turns out to be
more than one piece of work into an epic. One of strict
(only on a strong signal, such as requirements that fall into groups that
could each ship alone), moderate (default: one strong signal, or two weak
signals together), or lenient (one strong signal or a single weak signal
is enough). Separate from spec_trigger_threshold, and never a stand-in for
it. At every level the agent must still name at least two speks that can
each be verified on their own, and code plus its docs, tests or config is
always one spek. Read live at the moment the agent decides whether to
offer, so a change here takes effect immediately.
auto_commit string offWhether Spek records the agent’s work in git for you. One of
off (default: no automatic commits), workflow (one commit in each
changed repository when a spek, plan or implementation completes), or
full (as workflow, plus a commit after each milestone of an
implementation). Commits use your own git, run your hooks, use your
identity and signing settings, and are never pushed. When it is on and a
registered repository has uncommitted changes as a workflow starts, the
agent asks whether to commit them first. A repository that isn’t a git
repository is skipped.
debug section debug.enabled: falseDebug logging. Set debug.enabled: true to write a JSONL log of every
command to .spektacular/debug/session-log.jsonl, useful when reporting
issues or developing a new plugin. See the Debugging page
for the full walkthrough.
spec section specsHow speks are stored and identified.
spec.provider: storage backend; only file ships today.spec.id_method: spek naming scheme. One of timestamp (default),
counter (sequential numbers), or external (the caller supplies an
id with each spek).spec.config.directory: where the file provider writes speks. Defaults
to specs, relative to the folder holding config.yaml (the same rule as
repos[].location), so speks land in .spektacular/specs. A directory
outside the project is refused.Every spek record also carries lifecycle metadata: a created date, a document status, and, once resolved, a closed date, tracked automatically without any extra configuration.
Locations the CLI reports for speks, such as a list’s path, are relative
to the folder holding config.yaml, for example specs/<name>.md. Speks
are addressed by name, never by this location: see
Documents.
plan section plansHow plans are stored.
plan.provider: storage backend; only file ships today.plan.config.directory: where the file provider writes plans. Defaults
to plans, relative to the folder holding config.yaml, so plans land in
.spektacular/plans.plan.task_id.provider: where task identifiers come from; uuid
(default) issues random UUIDs. See Plan tasks.Every plan record also carries lifecycle metadata: a created date, a document status, and, once resolved, a closed date, tracked automatically without any extra configuration.
Locations the CLI reports for plan documents, such as a list’s path or
the status plan_path, are relative to the folder holding config.yaml,
for example plans/<name>/plan.md. Plan documents are addressed by the
feature name and a document name, never by this location: see
Documents.
changelog section changelogHow completed-feature changelog records are stored.
changelog.provider: storage backend; only file ships today.changelog.config.directory: where the file provider writes changelog
records. Defaults to changelog, relative to the folder holding
config.yaml, so records land in .spektacular/changelog.A record is written automatically at the end of every implement run,
one flat markdown file per feature, covering what was built, why it
matters, and how the outcome differed from the plan. Every changelog
record also carries the same lifecycle metadata as speks and plans: a
created date, a document status, and, once resolved, a closed date.
Locations the CLI reports for changelog records, such as a list’s path,
are relative to the folder holding config.yaml, for example
changelog/<name>.md. Records are addressed by name, never by this
location: see Documents.
epic section epicsHow epics are stored, and how implementation treats a dependency between an epic’s speks that is not implemented yet.
epic.provider: storage backend; only file ships today.epic.strict_dependencies: what happens when you start implementing a
spek whose dependencies are not all implemented. false (default)
warns, names each unmet dependency and its state, and lets you continue,
recording the override in the changelog. true refuses, and offers to
implement the first unmet dependency that is ready instead.epic.config.directory: where the file provider writes epics. Defaults
to epics, relative to the folder holding config.yaml, so epics land
in .spektacular/epics. The directory is created the first time an epic
is written, never by init. A directory outside the project is refused.init writes this section for new projects and migrate adds it to
existing ones. Using epics stays optional: a project that never splits a
spek sees no change in behaviour.
knowledge section Ordered list of the shared knowledge stores the project itself owns, such
as a team handbook. Each repository declares its own store in its
repo.yaml, not here.
knowledge.sources[].name: the name this store is addressed by. Must be
unique among the project’s own stores.knowledge.sources[].provider: storage backend; only file ships
today.knowledge.sources[].config.location: where the file provider reads
knowledge from. Relative paths resolve from the folder holding
config.yaml, the same base a repos entry uses.design section Ordered list of the design sources the project declares. A design document holds the worked design a feature is built to, and a spek references one rather than restating it. Design sources are declared by the project only; a repository does not declare its own.
design.sources[].name: the name this source is addressed by. Must be
unique among the project’s design sources.design.sources[].provider: storage backend; only file ships today.design.sources[].config.location: where the file provider reads and
writes design documents. Relative paths resolve from the folder holding
config.yaml, the same base a repos entry uses. The location may sit
outside the project, and is never rewritten on save.A source can hold both kinds of design document side by side. A design your team already had is stored exactly as supplied, gaining no frontmatter and never being reformatted; a design Spek authors with you carries the same lifecycle record every spek and plan carries.
See the Design Documents page for the full reference.
repos section How a project registers its member repositories. Each entry names one
repository and locates the folder that holds the repository’s own
repo.yaml:
repos[].name: the repository’s project-local name, unique within
this project and slug-safe; plans and changelog entries refer to
repositories by it.repos[].location: the folder holding the repository’s repo.yaml,
absolute or relative to the folder holding this config.yaml.
Nothing is appended to it, so the project’s own footprint is . and
a repository folder inside the project is ../repos/<name>. The
older local key is still accepted and means the same thing; it is
written back as location.repos[].provider: the repository’s provider. Only git ships today.repos[].dependencies: the project-local names of other registered
repositories this one depends on.Where the repository’s code lives is the repository’s own concern,
declared by source in its repo.yaml (below). The older address
key is no longer accepted here: a configuration that still carries it
fails to load with an error naming the repository, and its value moves
to that repository’s source.
A repository’s description, role, and tags are not declared here either. They live in the repository’s own configuration file, described below.
What a member repository is: its description, role, tags,
where its code lives, and its own knowledge sources and changelog
provider. Every member repository carries its own repo.yaml,
distinct from the project’s own .spektacular/config.yaml above. The
folder holding that file is the repository’s location, and the source
key says where its code is, relative to that same folder. It is created
as part of the repository’s footprint, either when it is registered
with repo add or during a project’s initialization cascade over its
already-registered repositories. It carries no reference back to any
project that registers it, so the same repository can belong to any
number of projects while describing itself in exactly one place. A
complete example, for a documentation site:
schema: 2 # settings format version; `migrate` raises itwritten_by: 0.16.0 # the Spektacular version that last wrote this file
description: Marketing and documentation site, built with Astrorole: documentationtags: - docs - websitesource: provider: file # file or git config: location: .. # or git@github.com:org/docs.git for git
knowledge: provider: file config: location: knowledge
changelog: provider: file config: directory: changelogDescriptive metadata, the location of the repository’s code, and the
repository’s own knowledge sources and changelog provider, shown
wherever this repository’s details are surfaced, such as
spektacular repo list or the repository roster an agent sees during
planning and implementation. Every relative path in this file, the
source included, resolves from the folder holding the file.
schema integer The settings format version of this repo.yaml, on its own count: a
repository file at format 2 sits beside a project file at format 3.
migrate raises it for every registered repository present on disk.
written_by string The Spek version that last saved this file, for diagnosis only.
description string A short account of what this repository is or does.
role string The role this repository plays, such as service, documentation, or
library.
tags list of strings Free-form labels for the repository, such as docs, website, or
backend.
source string .spektacular/Where this repository’s code lives. Either a file location (a plain
path or a file:// path, absolute, relative to the directory holding
repo.yaml, or using ${VAR}) or a git location (git://, ssh://,
https://, or user@host:path). A git location is cloned into the
project’s .spektacular/repos/<name>/ folder the first time the
repository is used and never fetched or pulled afterwards. When set,
repo list reports it as the repository’s root and workflows send
agents there; knowledge and changelog entries still land where this
file’s knowledge and changelog keys say, under the folder holding
repo.yaml. Leave it unset when the repository’s Spek files
sit inside its code. Not to be confused with the project-level
source in config.yaml, which records a git address for changelog
provenance only.
knowledge section knowledgeThis repository’s single knowledge store, holding what is true of its own code. The store is addressed by the name the project registered this repository under, so there is no name to set here and no more than one store to declare.
knowledge.provider: storage backend; only file ships today.knowledge.config.location: where the file provider reads this
repository’s knowledge from. Relative paths resolve against the folder
holding repo.yaml.See the Knowledge Base page for the full reference.
changelog section changelogSame shape as the project-level changelog key above, resolved from
the folder holding this file; this is where the repository’s own
derived changelog entries land.
Every settings file records the format version it was written in. When a
release changes that format, or when you install a newer Spek than
the one that installed your agent skills, commands stop with an error
naming migrate until the project is brought up to date. migrate,
init, version check and help always run, so the way out is always
reachable.
Preview every change first, which touches nothing on disk:
spektacular migrate --dry-runThen apply it:
spektacular migrateOne run:
config.yaml and every registered repository’s repo.yaml
present on disk, through as many formats as each file is behind.v<N>.old copy of each file it rewrites, named after the
format the file started atepic_split_threshold: moderate and the epic section (provider file,
strict_dependencies: false, directory epics)Re-running spektacular init <agent> applies the same upgrades before it
does anything else, so an existing project can also be brought current by
setting it up again. A file written by a newer Spek is refused
rather than converted: the error asks you to update Spek, and the
file is never rewritten.
Speks, plans, knowledge, and agents are all behind plugin interfaces. See what ships today and what's planned.