Stand up the Cargo workspace (Rust 2024, resolver=3) with kebab-core, kebab-parse-types, kebab-config, kebab-app, kebab-cli crates. Freeze every domain type, trait, ID recipe, error type, and CLI entry shape per the frozen design doc so that all subsequent component tasks compile against stable contracts.
Why now / why this size
Every other task imports kebab-core. If types or trait signatures wobble after this point, every downstream task spec drifts. This task is large but indivisible: types + traits + ID recipe + facade + CLI skeleton + wire schema stubs must land together so the rest of the workspace can compile against them.
Allowed dependencies
workspace [workspace.dependencies]: anyhow = "1", thiserror = "2", serde = { version = "1", features = ["derive"] }, serde_json = "1", time = { version = "0.3", features = ["serde", "macros"] }, uuid = { version = "1", features = ["v7", "serde"] }, blake3 = "1", tracing = "0.1"
kebab-parse-types: workspace deps + kebab-core ONLY (no parsers, no stores, no normalize). Defines parser intermediate representations per design §3.7b.
kebab-cli: workspace deps + kebab-core, kebab-config, kebab-app, clap = { version = "4", features = ["derive"] }
Forbidden dependencies
kebab-core MUST NOT depend on any other kebab-* crate.
kebab-parse-types MUST depend ONLY on kebab-core. No parser libraries (pulldown-cmark, pdf-extract, image, whisper-rs, …), no other kebab-* crate.
kebab-config MUST NOT depend on kebab-app, kebab-cli, parsers, stores, embedders, search, llm, rag, tui, desktop.
kebab-app MUST NOT yet depend on parsers/stores/embedders/search/llm/rag (those crates do not exist yet — facade methods stub out and return unimplemented!() or anyhow::bail!("not yet wired (Pn-i)")).
kebab-cli MUST NOT call any non-kebab-app crate directly.
All facade-returned wire objects emit schema_version per §2 (e.g., "answer.v1", "search_hit.v1").
Storage / wire effects
Filesystem: creates ~/.config/kebab/, ~/.local/share/kebab/, ~/KnowledgeBase/ only when kebab init runs; never on Config::load.
Wire schemas: ships docs/wire-schema/v1/{citation,search_hit,answer,ingest_report,doc_summary,chunk_inspection,doctor}.schema.json as stubs declaring the top-level schema_version and required fields per §2. Full property validation can land later.
DB: workspace ships migrations/V001__init.sql containing only §5.1 schema_meta + migrations tables (the full schema lands in p1-6's migration file or p0-1 may pre-stage the empty migrations directory; choose the former to keep this task within kebab-core/kebab-config/kebab-app/kebab-cli scope).
Logging: tracing initialized in kebab-cli; daily-rolling file in ~/.local/state/kebab/logs/.
Test plan
kind
description
fixture / data
unit
id_from deterministic across 1000 runs for fixed inputs
inline
unit
each id_for_* recipe matches design §4.2 byte-for-byte (verify against fixed expected hex)
inline
unit
to_posix collapses ./a//b.md → a/b.md and NFC-normalizes Korean
inline
unit
Citation::to_uri and parse round-trip for all 5 variants
kebab --help, kebab init, kebab doctor run; doctor reports config_loaded ✓ data_dir_writable ✓ even with no DB present (downstream checks may fail with hint)
tmp XDG_* env
build
cargo check --workspace and cargo test --workspace pass
repo
All tests must run with no network, no Ollama, no models.
docs/spec/ stubs exist linking to the frozen design (one file per: domain-model, ids, canonical-document, chunk-policy, citation-policy, module-boundaries, ai-generation-guidelines)
fixtures/ root directory created with all subdirectories that downstream tasks reference: fixtures/markdown/, fixtures/source-fs/, fixtures/search/lexical/, fixtures/search/hybrid/, fixtures/embed/, fixtures/vector/, fixtures/rag/, fixtures/eval/, fixtures/image/, fixtures/pdf/, fixtures/audio/. Each subdir gets a .gitkeep so it tracks. P1 ships at minimum fixtures/markdown/{simple-note,nested-headings,code-and-table}.md (per epic phase-0); other dirs stay empty until their phase lands.
No imports outside Allowed dependencies (CI deny check)
Real kebab-app business logic (functions stub with unimplemented!() or explicit bail!).
Risks / notes
ID recipe is the contract that every later record depends on. Any change after this task lands forces a parser_version / chunker_version / embedding_version cascade per §9. Treat changes as schema migrations and update the design doc first.
Newtype IDs use String (not [u8; 16]) to keep serde simple; tests must still enforce 32-char hex constraint on FromStr.
kebab-app stubs must use bail! not panic! so the CLI exits with code 2 cleanly per §10.