FAQ
Short answers to the questions a team actually asks when trialing MarkSpec.
What is a display ID?
A display ID is the human-readable identifier in the […] bracket on an entry
title line, for example STK_PRJ_0001. It encodes the entry type prefix
(STK), an optional domain segment (PRJ), and a zero-padded sequence number
(0001). Display IDs are mutable — you can rename STK_PRJ_0001 to
STK_AEB_0001 — and MarkSpec rewrites all references in the workspace when you
use the LSP rename command.
What is a ULID and why does MarkSpec assign one?
A ULID (Universally Unique Lexicographically Sortable Identifier) is a
26-character string like 01KPVVC9J2B1ZA64QZEMHF02PW. MarkSpec stamps one onto
each entry during markspec format and stores it as the Id: attribute.
The ULID is immutable. Once assigned it never changes, even if the display ID or title is renamed. Traceability links between projects and external tools (JIRA, DOORS) reference the ULID, not the display ID, so renaming an entry never breaks cross-tool links.
How does MarkSpec discover project.yaml?
markspec walks up the directory tree from the current working directory until
it finds a project.yaml file. The directory containing that file becomes the
project root. If no project.yaml is found, commands that require project
context (compile, show, context, dependents, report, next-id,
doc build, book build) exit with an error. format and validate work
without a project.yaml.
Can I use MarkSpec without a profile?
Yes. markspec format and markspec validate work without a profile — they
apply built-in formatting rules and lint checks. Commands that need type
vocabulary (compile, create, next-id) require a profile to know the
display-ID patterns for each type.
To activate a profile, create a .markspec.yaml in the project root:
profiles:
- ./profiles/markspec.yaml
See the Profile guide for the full configuration reference.
What do exit codes 0, 1, and 2 mean?
| Code | Meaning |
|---|---|
0 | Success — no errors, no warnings |
1 | Error — validation failed or command error |
2 | Warnings only — validate found warnings but no errors |
In CI, treat exit code 2 as a pass or a fail depending on your policy. Pass
--strict to markspec validate to promote warnings to errors (exit code 1).
Where should I put my Markdown files?
Anywhere you like — MarkSpec does not enforce a directory layout. The convention used in this project is:
docs/— Markdown files containing requirements and architecture descriptionssrc/— source code with doc-comment entries (Rust///, Kotlin/**)
Pass explicit paths or globs to commands that need them:
markspec validate docs/requirements.md
markspec compile "docs/**/*.md" src/main.rs
What is the difference between format and validate?
| Command | What it does | Writes files? |
|---|---|---|
markspec format | Stamps ULIDs, normalizes indentation and attribute order | Yes (in place) |
markspec validate | Checks broken references, missing IDs, duplicates, lint rules | No |
Run format first (or as a pre-commit hook via markspec hook) to ensure every
entry has a ULID before committing. Run validate in CI to catch broken
traceability links.
How do I set up the LSP in my editor?
- VS Code — install the
markspec-ideextension fromeditors/vscode/in the repository. See CLI guide — VS Code. - Neovim — add a
vim.lsp.startautocmd. See CLI guide — Neovim. - Other editors — point your LSP client at
markspec lsp. Transport: stdio. See CLI guide — Other editors.
Can I run multiple profiles at once?
The current implementation supports one active profile per project. If multiple
profiles are listed in .markspec.yaml, a PROFILE-LOAD-006 warning is emitted
and only the first is used. Profile stacking (extends chains) is the recommended
way to compose vocabulary. See the Profile guide.