Imports and Dependencies

As projects grow, a single spec becomes hard to read and hard for CodeSpeak to reason about. Spec dependencies let you split your project into focused, composable specs with clear boundaries.

Example: a memo app

A CLI memo app split into two specs โ€” one for storage, one for everything else.

storage.cs.md:

# Memos storage

Each memo has:
- content
- creation date

Memos are stored in a plain text file in JSON format

main.cs.md:

---
import storage.cs.md
---
# memo app

This is a simple Python CLI app that supports simple creation and retrieval of memos

## CLI commands

`memo add <memo content>` - creates a new memo with given content
`memo show` - shows all memos, grouped by day of the creation
`memo find <substring>` - finds a given memo by substring
`memo delete <substring>` - deletes a given memo by substring

## UI

App uses `rich` library for pretty terminal UI

The import directive

The frontmatter at the top of main.cs.md declares the dependency:

---
import storage.cs.md
---

This tells CodeSpeak that main.cs.md depends on storage.cs.md. When building main.cs.md, CodeSpeak builds the storage spec first, then builds the main spec with full knowledge of what storage provides.

You can import multiple specs, and imports are transitive โ€” if A imports B and B imports C, CodeSpeak builds all three in the right order.

Building

codespeak build main.cs.md --skip-tests
Processing spec 1/2: storage.cs.md
...
Processing spec 2/2: main.cs.md
App built successfully.

CodeSpeak processes specs in dependency order: storage.cs.md first, then main.cs.md. Each build step focuses on one concern.

Changing one spec

Switch storage from JSON to SQLite by editing just one line:

 # Memos storage

 Each memo has:
 - content
 - creation date

-Memos are stored in a plain text file in JSON format
+Memos are stored in an sqlite file

Rebuild:

codespeak build main.cs.md --skip-tests

CodeSpeak detects that storage.cs.md changed and rebuilds it. The main spec hasn't changed, so CodeSpeak skips it. The storage module's interface stays the same โ€” main.py continues to work without modification.

Importing from subdirectories

Import paths can include subdirectories, separated by forward slashes:

---
import lib/base.cs.md
import utils/helpers.cs.md
---
# My app

Uses shared library and utility specs.

All import paths are relative to the project root. You don't need ./ โ€” in fact, CodeSpeak forbids it along with several other path forms:

---
// โœ“ Valid
import storage.cs.md
import lib/base.cs.md
import utils/helpers.cs.md

// โœ— Invalid โ€” will produce an error
import ./storage.cs.md
import ../shared/utils.cs.md
import /absolute/path/to/spec.cs.md
import ~/my-specs/common.cs.md
import lib\..\storage.cs.md
---

Path rules:

  • Paths must be relative to the project root โ€” no ./, ../, or absolute paths
  • No . or .. components anywhere in the path
  • Use forward slashes only โ€” backslashes are rejected

Key behaviors

  • import in frontmatter declares a dependency between specs
  • CodeSpeak builds in dependency order โ€” dependencies first, then the specs that use them
  • Only changed specs are rebuilt โ€” unchanged specs are skipped
  • Changes stay local โ€” modifying one spec doesn't require touching its dependents if the interface stays the same