Motivation
The CLI is a first-class surface (R44: every capability is exposed via PHP, HTTP, and MCP). Operators run ingestion, retention, graph rebuilds, and the Auto-Wiki phases fromphp artisan. This page lists the
commands grouped by concern with their exact signatures. Run php artisan <command> --help for the authoritative, version-current option list.
Conventions
- Tenancy. Most commands accept
--tenant=(default: currentTenantContext, usuallydefault). - Dry runs. Destructive sweeps accept
--dry-runto report without mutating. - Retention overrides. Prune commands accept
--days=N;0disables that rotation. - Path arguments. Commands that take a KB
source_path(e.g.kb:delete, the folder walk inkb:ingest-folder) normalise it throughKbPathand resolve it relative toKB_PATH_PREFIX. (kb:ingestbuilds its path more directly, so match the path you ingested with when deleting.)
Ingestion
| Signature | Purpose |
|---|---|
kb:ingest {path} {--project=} {--title=} {--disk=} | Ingest a single document via the configured disk. Exits non-zero when the disk returns no bytes for an existing file, or when the document IS committed but its conversion artifact could not be published (the pointer is kept as missing; re-running the command or kb:artifacts-backfill repairs it). |
kb:ingest-folder {path?} {--project=} {--tenant=} {--disk=} {--pattern=} {--recursive} {--sync} {--limit=0} {--dry-run} {--prune-orphans} {--force-delete} | Walk a folder and dispatch one ingestion job per supported file. In --sync mode a document ingested whose conversion artifact could not be published is counted as ingested, listed apart (ingested, artifact not published) and makes the command exit non-zero. |
kb:doc-versions {document} {--tenant=default} {--limit=} {--offset=0} {--diff=} | v8.36 — list a document’s version family with actor, reason, stored artifact and content hash, newest first, bounded and paged (--limit, at most KB_VERSIONS_TIMELINE_LIMIT; --offset skips the newest; a larger family prints Showing versions A-B of M (--limit, max N; --offset to page).; a non-numeric value fails); --diff=FROM:TO prints an artifact-aware diff naming the source of each side (both ids resolved against the whole family, not the listed page). Read-only. See Documents & OCR |
kb:artifacts-backfill {--project=} {--tenant=default} {--dry-run} | v8.36 — store or repair the conversion artifact of live rows, each judged on its own metadata.source_retention (rows stamped reference_only are intentionally_missing, a verified pointer is already_stored, a missing or corrupt file behind a pointer is repaired, a verified pointer without a recorded content_hash gets it); the reconversion runs under the row’s own contract (its recorded OCR run is read back even after KB_SOURCE_RETENTION moved to reference_only) and writes only when it hashes to the recorded document_hash (hash_mismatch writes nothing); a write then applies the row’s retention contract (a markdown_only row’s original is dropped under the same reference-aware gate as ingest, source_dropped stamped); --dry-run never spends nor drops (ocr_unverified for rows that would need a fresh OCR run); a verified artifact — written or already there — finalizes the row’s markdown_only contract (originals_dropped), and a row on a disk this deployment cannot resolve or reach (the disk refuses the source probe) is disk_unavailable, reported and skipped — never source_missing, never a crash mid-corpus. The command exits non-zero when any row was source_missing, conversion_failed or disk_unavailable (hash_mismatch is informational); --dry-run predicts the same exit code. Operator-only (R44 exception). |
kb:ocr {document} {--status} {--tenant=default} | v8.36 — show the OCR status of a document (--status) or queue a forced OCR re-run through the standard ingest job (metadata.ocr.force=true); refuses when KB_OCR_ENABLED=false. See Documents & OCR |
Promotion & deletion
| Signature | Purpose |
|---|---|
kb:promote {path} {--project=} {--dry-run} {--auto-approve} | Promote a local canonical markdown file to the KB (PromotionFlow) |
kb:delete {path} {--project=} {--force} {--soft} {--keep-file} | Delete a document (DeleteDocumentFlow); --force = hard delete — while conversion artifacts are on, the source removal runs under the storage key’s lock (reference scan, .ocr/ purge and delete under it); a key another writer holds, a cache store that cannot lock or a lapsed lock keeps the file for kb:prune-orphan-files and reports file_deleted: false, never a failed delete |
Canonical graph & health
| Signature | Purpose |
|---|---|
kb:rebuild-graph {--project=} {--tenant=} {--no-truncate} {--sync} | Rebuild kb_nodes + kb_edges from canonical docs |
kb:validate-canonical {--project=} {--from-disk} {--disk=} | Validate canonical frontmatter; report per-file schema errors |
kb:health-recompute {--tenant=} {--emit-events} | Recompute canonical KB health snapshots |
kb:stale-review-sweep {--tenant=} {--months=} {--limit=500} {--dry-run} | Notify reviewers of stale documents |
Auto-Wiki engine
| Signature | Phase |
|---|---|
kb:evidence-tier {document} {--set=} {--tenant=default} {--actor=cli} | P1b — show/set evidence tier |
kb:wiki-link {document} {--tenant=default} | P2 — rebuild auto-wiki graph for a doc |
kb:synthesize-concepts {project} {--tenant=default} {--limit=} | P3 — synthesise concept pages |
kb:wiki-index {--project=} {--tenant=default} | P4 — rebuild indices |
kb:wiki-lint {--project=} {--tenant=default} {--fix} | P5 — lint (dangling/orphan/stale) |
kb:wiki-navigate {project} {--seeds=} {--depth=} {--tenant=default} | P6 — multi-hop BFS navigation |
kb:wiki-review {document} {--tenant=default} | P7 — cross-model review |
kb:apply-suggestion {analysis} {type} {target} {--tenant=default} {--actor=cli} | P8 — apply change/delete suggestion |
kb:wiki-maintain {--project=} {--tenant=default} {--fix} {--backfill=} | P9 — scheduled maintenance |
kb:wiki-promote {document} {--discard} {--tenant=default} | P10 — promote auto→human |
Retention & cleanup
| Signature | Purpose |
|---|---|
kb:prune-deleted {--days=} {--tenant=} {--dry-run} | Hard-delete soft-deleted docs past retention; since v8.36 prints files_kept=N per tenant when non-zero (rows whose source file was kept — still referenced, or its storage key held/unlockable/lapsed; kb:prune-orphan-files takes them later, and it is not a failure) |
kb:prune-archived-versions {--tenant=} {--keep=} {--dry-run} | Drop old archived versions beyond the cap through the deleter’s row path (chunks, graph, deprecation audit); since v8.36 also removes each pruned version’s conversion artifact and unreferenced OCR run, sweeps stale .tmp files no live writer leases (artifact_temps_in_flight counts the leased ones, kept whatever their age) + orphan artifacts on every recorded artifact namespace (artifact_namespaces_skipped when one cannot be resolved), picks a family’s surplus with NULL indexed_at last on every driver (an undated archived row is the oldest, never the kept newest), re-checks each candidate under a lock so a version restored meanwhile is skipped (restored_meanwhile), removes every artifact through the deleter’s reference gate under the artifact path’s lock (a path an identical ingest recreated meanwhile is kept: artifacts_kept per tenant, artifact_orphans_kept on the sweep line — the orphan sweep reports it in --dry-run too, the per-tenant prune reports nothing in a dry run), and exits non-zero reporting *_failed counts when the disk refused a removal |
kb:prune-embedding-cache {--days=} {--tenant=} {--dry-run} | Evict cache rows past retention (not a full flush) |
kb:prune-orphan-files {--disk=} {--project=} {--dry-run} | Delete KB files with no matching row — a source younger than KB_ORPHAN_SOURCE_GRACE_SECONDS (default 3600 s, 0 disables) is kept first of all, because an ingest reads and converts its source before it takes the storage key’s lock; then each deletion re-checks the references and, while conversion artifacts are on, runs under that lock (a row that took the path meanwhile, a writer holding its key, or a file still inside the grace keeps it: kept_meanwhile; --dry-run previews the grace); since v8.36 also removes dangling .ocr/ trees and stale OCR runs older than KB_OCR_PURGE_GRACE_SECONDS; since v8.36 the disk is walked once, lazily, sources judged in batches of 1000 (R3); the candidate lists are bounded by KB_ORPHAN_SCAN_MAX_ITEMS (default 50 000; not switchable off while the walk collects in memory — a non-positive value is the default) — a sweep that hits the cap reports scan_truncated=1 and exits non-zero, and the next run continues; a walk the disk refuses is a reported failed sweep that deletes nothing, and an OCR tree whose source the disk refuses to probe is kept and counted (tree_probe_failed, exit non-zero) |
chat-log:prune {--days=} {--tenant=} {--dry-run} | Rotate chat logs |
notifications:prune {--days=} {--tenant=} | Rotate notification events |
widget:prune-sessions {--days=} {--tenant=} {--dry-run} | Rotate widget sessions |
admin-audit:prune {--days=} | Rotate admin command audit |
admin-nonces:prune {--days=} | Purge expired command nonces |
collections:reevaluate {--tenant=} {--collection=} | Re-evaluate collection membership |
Insights, evaluation & compliance
| Signature | Purpose |
|---|---|
insights:compute {--date=today} {--tenant=} {--force} | Daily AI-insights snapshot, one row per tenant |
eval:nightly {--dry-run} {--status} {--prune-only} | Eval-harness baseline run; alert on macro_f1 regression |
notifications:digest-weekly {--tenant=} | Email weekly notification digests |
compliance:digest-quarterly {--tenant=} {--at=} | Quarterly compliance reports for opted-in tenants |
Benchmarks
| Signature | Purpose |
|---|---|
kb:benchmark {--stub} {--with-answers} {--gate} {--project=benchmark} {--k=5} {--corpus=} {--queries=} | Retrieval-quality benchmark (nDCG/MRR/precision/citation/refusal/graph) |
kb:make-benchmark-fixtures | Regenerate the binary (PDF + DOCX) benchmark corpus |
Case-study email datasets
| Signature | Purpose |
|---|---|
demo:generate-case-study-emails {--profile=} {--seed=} {--catalog-version=} {--output=} {--force} {--check} {--stats} | Generate or byte-check deterministic JSONL datasets offline |
demo:validate-case-study-emails {--profile=} {--dataset-version=} {--dataset-root=} | Validate manifest, hashes, records, threads, catalogs, and canaries |
mail:seed-imap {--mailbox=*} {--project=*} {--all} {--dataset-version=} {--profile=} {--resume} {--estimate-cost} {--purge-dataset} {--purge-only} {--purge-all-seeded} {--purge} {--preview-purge} {--confirm-token=} {--actor=} {--dry-run} | Offline preflight or local/testing-only IMAP delivery; destructive modes require an exact single-use token |
Auth, MCP & widget
| Signature | Purpose |
|---|---|
auth:grant {email} {role} {--project=} | Grant a Spatie role (and optional project membership) |
system-admin:grant {email} {--yes} | Grant audited global platform access plus the companion tenant role |
system-admin:revoke {email} {--yes} | Revoke global platform access, retain tenant super-admin, and protect the final active operator |
askmydocs:mcp:connect {--server=} {--tenant=} {--token=} {--name=askmydocs} | Print a Claude Code .mcp.json snippet for the MCP server |
widget:emit-secret {public_key} | Emit a new widget secret (sk_…) — shown once |
widget:identity-credential {status|enable|disable|rotate} {key} {--tenant=default} {--expected-version=} {--force} | Inspect or mutate the audited server-only ik_; mutations require the current version and show a new secret once |
Worked example
# ingest a folder, then rebuild the graph synchronously
php artisan kb:ingest-folder docs/ --project=handbook
php artisan kb:rebuild-graph --project=handbook --sync
# dry-run a retention sweep before committing to it
php artisan kb:prune-deleted --days=30 --dry-run
# run an Auto-Wiki phase end-to-end on one document
php artisan kb:wiki-link 4213 --tenant=acme
php artisan kb:wiki-review 4213 --tenant=acme
php artisan kb:wiki-promote 4213 --tenant=acme
Scheduler & maintenance
Which of these run on a schedule, and when.
HTTP API reference
The same capabilities over HTTP.