Installation
# Core CLI only (list, validate, concept subcommands — JSON output)
pip install -e . # or: uv sync
# With semantic search capability
pip install -e ".[search]"
# Or with fully local semantic search
pip install -e ".[local]"
# Full setup: search + build tools + query server
pip install -e ".[search,build,server]"
| Extra | Packages | Commands |
|---|---|---|
| (none) | click, pyyaml, numpy | list, validate, concept subcommands |
[search] |
voyageai, openai | search, dedup |
[local] |
fastembed | Offline search, dedup, and index builds |
[build] |
litellm, jsonschema | Schemafier pipeline, --format=human |
[server] |
fastapi, uvicorn, pydantic | HTTP query server |
scull <command> [arguments] [options]
Every command that produces output takes --format to switch between human-readable and JSON (get/caveats/shape accept --format json|human; context/list/search/related/dedup accept --format text|json). Core install requires only click, pyyaml, and numpy. Optional features require additional packages:
| Extra | Packages | Commands |
|---|---|---|
| (none) | click, pyyaml, numpy | list, validate, concept subcommands (JSON output) |
[search] |
voyageai, openai | search command, embedding-based dedup |
[local] |
fastembed | Offline search, embedding-based dedup, local index builds |
[build] |
litellm, jsonschema | --format=human for get/caveats (LLM reconstitution), scull-schemafier pipeline |
[server] |
fastapi, uvicorn, pydantic | Query server (uvicorn scull.schemafier.server.main:app) |
Environment Variables
| Variable | Purpose | Default |
|---|---|---|
SCULL_SCHEMA_PATH |
Override schemas directory location | Auto-discovered (schemas/ from cwd) |
SCULL_EMBED_PROVIDER |
Embedding provider (voyage, openai, or local) |
"voyage" |
VOYAGE_API_KEY |
API key for Voyage AI | unset |
OPENAI_API_KEY |
API key for OpenAI | unset |
SCULL_EMBED_MODEL |
Model name override (e.g., "text-embedding-3-small") |
Provider default |
SCULL_EMBED_CACHE_DIR |
Local model download/cache directory | FastEmbed default |
SCULL_EMBED_TIMEOUT |
Per-request timeout (seconds) for the embed provider's client | 10 |
SCULL_EMBED_MAX_RETRIES |
Client-level retry count on transient embed failures | 1 |
SCULL_MODEL |
Default LLM model for --format=human |
unset |
The nearest scull.yaml in the current directory or its parents may provide the corresponding
project defaults without repeated environment variables:
defaults:
schemas_dir: schemas
kg_dir: kg
embed_provider: local
embed_cache_dir: .cache/embeddings
Commands
scull list [--format text|json]
List all available concepts with field and caveat counts. Human-readable output shows a table with aligned columns; --format json outputs structured data. (--json still works as a deprecated alias for --format json.)
$ scull list
Concept Fields Caveats Status
─────────────────────────────────── ──── ───── ────
deployment_config 4 12 ⚠ needs_review
job_runtime 8 15
...
$ scull list --format json
[{"name": "deployment_config", "fields": 4, "caveats": 12, "needs_review": true}, ...]
scull validate [--release]
Validate all schema files against required structure. Returns exit code 0 on success, 1 on errors. Output uses color-coded checkmarks/error counts when running in a terminal.
Unreadable files, invalid YAML or schema shapes, unsupported format versions, duplicate concept
names, dangling or malformed caveat attachments, stale content hashes, and an invalid
configured schema directory are validation errors. They fail the command even when other
schemas are valid; a parse warning cannot turn an invalid file into a successful validation.
An existing directory containing no schema files reports No schemas found. and exits 0.
--release additionally rejects an empty schemaset, needs_review: true, missing approval
metadata, and approval fingerprints made stale by any later edit. Passing it confirms structure and
a current human-review record, not factual accuracy or completeness.
$ scull validate
✓ 18 schema(s) valid.
$ echo $?
0
Errors are numbered and grouped by concept:
✗ 3 validation error(s):
1. ERROR: deployment_config.fields.values: missing 'value_type'
2. ERROR: query_operators.caveats.div-by-zero: missing 'evidence_hash'
3. ERROR: job_runtime.caveats.retry-loop: invalid severity 'critical'
scull get <concept> <field> [<field> ...] [--format json|human] [--model MODEL]
Get one or more field definitions from a concept. Default is raw JSON (zero inference). With
--format=human, exactly one field is accepted and an LLM renders prose (requires [build] extra +
--model).
$ scull get deployment_config values
{
"values": {
"value_type": "map[string]string",
"description": "...",
"confidence": "high"
}
}
$ scull get deployment_config values --format=human --model provider/model
Values is a map of string keys to string values.
...
scull caveats <concept> [--severity high|medium|low] [--format json|human]
List caveats for a concept. Human-readable output groups by severity level (high → medium → low), showing numbered entries with summary, evidence preview, and applies_to hints. --severity filters to a single level.
$ scull caveats deployment_config
Caveats for deployment_config
[HIGH] Configuration must exist before a workload references it...
[MEDIUM] A workload and its configuration must share a scope...
$ scull caveats deployment_config --severity high
Caveats for deployment_config
[HIGH] Configuration payloads have a fixed size limit...
[HIGH] Configuration values are not an encrypted secret store...
scull context <concept> <field> [...] [--situation TAG] [--detail] [--format json|text]
Return named field definitions together with every caveat attached to any requested field and every
general caveat for the concept. Multiple fields may be separate arguments or comma-separated. An
attached caveat that covers multiple requested fields appears once and retains its full
applies_to list.
This command reads only schema YAML. It does not require a KG, embedding provider, API key, account, or network connection.
Repeat --situation to supply curated usage tags. Tagged caveats are returned only when their tag
hierarchy overlaps; caveats with no applies_when metadata remain unconditional. Omitting the option
returns the complete set, preserving the conservative default for existing callers and schemas.
$ scull context schema schema_hash sources
$ scull context schema schema_hash,sources --format text
$ scull context deployment_config values --situation payload.size
The default JSON is compact for agents. It separates caveats.attached from caveats.general and
keeps field definitions, qualified paths, required scopes, concise constraints, examples/default
annotations, completeness, and inspection links without full interpretation records. It also
includes schema provenance and review state. Add --detail for complete scoped records, or use
scull inspect-schema with a returned rule link for bounded original evidence.
Compact mode groups artifact warnings by kind and count instead of repeating every mechanical
warning record.
scull search <query> [--top-k N] [--kg KG_DIR] [--concepts C1,C2] [--format text|json]
Semantic search across all embedded concepts using hybrid scoring (cosine similarity + lexical
overlap boost). Results are bounded semantic field units. A retrieved field bundle expands its
members without consuming more result slots, and reviewed attached caveats are nested with explicit
Applies when conditions. These are conditional context, not claims that the query satisfies the
condition. The default text format is the recommended agent interface. Requires [search] for
Voyage/OpenAI or a supported local embedding extra.
$ scull search "how do I make config immutable"
Results for: how do I make config immutable
Score Type
1.0000 FIELD UNIT [payments]
immutable: When true, prevents changes to data and binaryData...
HIGH Existing consumers are not restarted automatically...
Applies when: consume.runtime (conditional context)
Options:
--top-k N: Number of results (default: 5)--concepts runtime_*: Restrict search to specific concepts (comma-separated)--max-caveats-per-unit N: Bound nested caveats for each unit (default: 8)--max-caveats-total N: Bound nested caveats for the response (default: 40)--format json: Output the same structured semantic units and truncation metadata as JSON
If caveats are truncated, text and JSON expose the omitted count and a deterministic context
follow-up instead of silently dropping the remaining context.
scull related <concept> [field]
Show caveats related to a concept, optionally filtered to a specific field. Groups by field, showing caveat summaries with severity tags. This reads graph edges from the index but does not embed the query or call an embedding provider.
$ scull related deployment_config
Caveats for deployment_config
(general) (6)
[HIGH] Configuration must exist before a workload references it...
data (17)
[HIGH] Configuration payloads have a fixed size limit...
[HIGH] Configuration values are not an encrypted secret store...
scull dedup [--threshold FLOAT] [--format text|json]
Show near-duplicate caveats detected by embedding similarity during KG build. Reports pairs exceeding the cosine similarity threshold, with scores, IDs, and summaries truncated for review. Useful for manual deduplication decisions.
$ scull dedup
Found 67 near-duplicate pair(s):
Pair 1 Score: 0.9821 [deployment_config]
A: mounted-values-not-refreshed
A workload using a mounted configuration snapshot will not receive updates…
B: mounted-snapshot-no-auto-update
A mounted configuration snapshot does not receive later changes…
Tip: Review these pairs with 'scull caveats <concept>' to decide which to remove.
Options:
--threshold 0.95: Higher threshold means fewer, more similar pairs (default: 0.90)
scull concept <name> list-fields
List all field names for a concept with type and confidence columns.
$ scull concept query_operators list-fields
Field Type Confidence
─────────────────────────────── ──── ────────
bitwise_operators string medium
pipe_operator operator medium
try_operator operator medium
cast_operator operator medium
scull concept <name> get <field> [--format json|human]
Alias for scull get <concept> <field> via the concept subgroup. Same options apply.
$ scull concept query_operators get pipe_operator
scull concept <name> caveats [--severity LEVEL]
Alias for scull caveats <concept> via the concept subgroup. Same options apply.
$ scull concept query_operators caveats --severity high
Color Support
All commands auto-detect whether stdout is a TTY and adjust output accordingly:
- Terminal sessions: ANSI colors for severity levels (red/yellow/blue), green scores, cyan matched terms
- Pipes/redirects: Colors disabled automatically
Explicit control: colors follow standard terminal detection heuristics. To force colors in non-TTY contexts, set CLICOLOR=1.