# Matryca Plumber - AI Agent Context & Execution Guide (v2.1.0a3 preparation) > **SYSTEM DIRECTIVE FOR AI AGENTS:** You operate on the user's **local Logseq OG vault** via Matryca Plumber. > **CRITICAL RULE:** DO NOT `git clone` this repository. DO NOT `pip install`. Run the **PyPI** release with **`uvx`** so you use a real, versioned wheel — not a guessed dev tree. Canonical copy (2026 standard path): `.well-known/llms.txt` (same content as this file). > **v2.0.0 stable contract:** the external Shadow read cache is default-on; `MATRYCA_SHADOW_DB_ENABLED=false` remains the emergency Markdown/BM25 opt-out, and Logseq Markdown remains authoritative. v2.0.0 was qualified with `logseq-matryca-parser` 1.7.1, while package metadata accepts `>=1.7.1,<2.0.0`; always record the exact parser resolved by a fresh installation. The stable contract includes Strict Read Only with an external derived cache and fail-closed health/fallback behavior. Current operator behavior: `docs/knowledge/architecture/shadow-db.md`. Release evidence: `docs/quality/issue-bodies/v2-rc-stable-readiness.md`. > **Historical v2.0.1rc1 artifact scope:** the published RC1 `read_graph_data` handler adds the bounded `journal_day` target for one ISO-dated canonical journal. It returns source-digest provenance, reads Markdown without querying or initializing Shadow, and never mutates the graph. Its exact-artifact qualification record does not qualify later source revisions: `docs/quality/V2_0_1_RELEASE_QUALIFICATION_PLAN_2026-08-23.md`. > **Experimental v2.1.0a3 preparation:** the next proposed prerelease prioritizes an offline, content-free OG identity/topology process gateway for later Trama evaluation, with planned Linux x86_64 and macOS arm64 qualification on CPython 3.12/3.13. Preparation is not publication, installed-runtime qualification, Trama admission or stable support; do not install `matryca-plumber==2.1.0a3` until its public artifact and profile evidence are independently verified. Stable `v2.0.0` remains the default. Active plan: `docs/quality/V2_1_0A3_RELEASE_QUALIFICATION_PLAN_2026-10-22.md`. > **Historical v2.0.1 prereleases:** RC3 is published; its exact artifact record is `docs/releases/v2.0.1-rc.3-GITHUB.md`. The signed RC2 tag and failed publication run remain historical and published neither destination. RC4 preparation was not published; its historical candidates and unfinished Windows, full Stage A and dual-profile Gate B obligations are preserved, not qualified or discarded. Supersession record: `docs/quality/RC4_TO_V2_1_0_SUPERSESSION_2026-10-16.md`. Windows gateway refusal is not Windows package qualification; no DB compatibility is claimed. > **v2.0.0-alpha.5 headline:** **Shadow hardening campaign closed** ([#261](https://github.com/MarcoPorcellato/matryca-plumber/issues/261)) — CTE depth-truncation status ([#289](https://github.com/MarcoPorcellato/matryca-plumber/issues/289) / [#291](https://github.com/MarcoPorcellato/matryca-plumber/pull/291)); state API absolute-path redaction ([#293](https://github.com/MarcoPorcellato/matryca-plumber/issues/293) / [#294](https://github.com/MarcoPorcellato/matryca-plumber/pull/294)); Axes 5–7 audit probes green; `MATRYCA_SHADOW_DB_ENABLED=false` by default. **Not an RC** — post-publish soak before beta/RC. Roadmap: `docs/roadmaps/ROADMAP_V2_PREPARATION.md`. > **v2.0.0-alpha.4 headline:** **Shadow FTS query length bound** — keywords over **512 Unicode characters** (post-`strip`) are rejected before FTS preparation or SQLite `MATCH` ([#279](https://github.com/MarcoPorcellato/matryca-plumber/issues/279) / [#286](https://github.com/MarcoPorcellato/matryca-plumber/pull/286)); Axis 4 FTS5 gate **fully green** — **52 pass, 0 xfail**. > **v2.0.0-alpha.3 headline:** **Shadow FTS hyphenated queries** — natural compounds like `state-of-the-art` route through shadow FTS5 without spurious generational fallback ([#277](https://github.com/MarcoPorcellato/matryca-plumber/issues/277) / [#282](https://github.com/MarcoPorcellato/matryca-plumber/pull/282)). > **v1.13.1 headline:** **Logseq Matryca Parser 1.6.0 alignment** — minimum dependency `logseq-matryca-parser>=1.6.0`; inherits **1.4.2** newline splice safety, resilient X-Ray reload, SYNAPSE cyclic-embed truncation; `_headless_append_child` mirrors parser newline normalization. Architecture: `docs/ARCHITECTURE.md`. > **v1.13.0 headline:** **Daemon & dispatch modularization** — `maintenance_daemon` split into focused `daemon_*` modules ([#58](https://github.com/MarcoPorcellato/matryca-plumber/issues/58)); `graph_dispatch` handler registry + **`GraphReadPort`** (v2 Phase 1, [#59](https://github.com/MarcoPorcellato/matryca-plumber/issues/59)). Maintainer map: `docs/CLEAN_CODE_ARCHITECTURE.md` · `docs/ARCHITECTURE.md`. > **v1.12.0 headline:** **Prompt Clean Architecture** — Tier-1 domain prompt builders (`src/agent/prompts/`), L0 write-safety validators before semantic commits, `SYSTEM_PROMPT.md` assembled from `docs/openspec/agent/` fragments (`make build-system-prompt`). Maintainer map: `docs/PROMPT_ARCHITECTURE.md` · `AGENTS.md`. > **v1.11.x:** **Tana → Logseq OG** via `matryca import tana` / MCP **`import_tana`** (dry-run default). **v1.11.1** aligned **`logseq-matryca-parser` 1.4.0**. **v1.11.2** refactors the **graph layer boundary** (`post_write` port, bounded RAM LRU caches, OCC `st_mtime_ns` page writes). Spec: `docs/openspec/tana-import.md` · architecture: `docs/ARCHITECTURE.md`. --- ## 0. Graph path (REQUIRED — no `--graph` flag) The v2.0.0 release does **not** accept `--graph` on the CLI. You **must** point at the vault root (folder containing `pages/` and usually `journals/`) with the environment variable **`LOGSEQ_GRAPH_PATH`**. **Set once per shell session (copy-paste):** ```bash export LOGSEQ_GRAPH_PATH="/absolute/path/to/your/logseq/graph" ``` **One-shot (inline env for a single command):** ```bash LOGSEQ_GRAPH_PATH="/absolute/path/to/your/logseq/graph" uvx matryca-plumber --help ``` If `LOGSEQ_GRAPH_PATH` is unset or invalid, graph commands return an error — fix the path before retrying. --- ## 1. Execution & Installation (PyPI / uvx) Matryca Plumber is on PyPI as **`matryca-plumber`**. Use **`uvx`** (uv tool runner); no permanent install required. **Entrypoint (console script):** ```bash uvx matryca-plumber ... ``` **Discover commands:** ```bash uvx matryca-plumber --help uvx matryca-plumber read --help ``` **Machine-readable JSON:** Global flag **`--json`** must appear **before** the subcommand: ```bash uvx matryca-plumber --json read page "My Project" ``` --- ## 2. Core CLI (v2.0.0) Subcommands: `read`, `search`, `mutate`, `refactor`, `lint`, `context`, **`import`**, `service`, `plumber`. Shorthand daemon/UI verbs (routed to `plumber`): `start`, `stop`, `status`, `ui`, `audit`, `cluster`. `read journal_day 2026-08-23` reads one canonical ISO-dated journal. It is a bounded, Markdown-authoritative read with explicit status/provenance; it does not initialize Shadow or modify the graph. Structured pagination uses the `read_graph_data` `journal_day` target rather than filesystem access. ### 2.0 Plumber commands — UI vs daemon (do not confuse) | Command | Starts | Does **not** start | |---------|--------|-------------------| | `status` / `ui` (or `plumber status` / `plumber ui`) | Sovereign UI + API on `http://127.0.0.1:8500` | maintenance daemon | | `plumber start` | background maintenance daemon | browser / UI server | | `plumber start --foreground` | foreground daemon (terminal logs) | browser / UI server | | `plumber stop` | — | stops daemon | **Lazy UI bootstrap (v1.9.10+):** `status` / `ui` bind `:8500` in seconds; the in-memory graph index loads on the first analytics request. **v1.9.11:** settings save, graph-path save, L1 provision, and **Start Engine** also use lazy bootstrap so large vaults do not hit the 10s UI fetch timeout. Use **Start Engine** in the UI or `plumber start` to run Phase 1/2 maintenance (the daemon subprocess loads the AST eagerly). **Common mistake:** `plumber start` alone does **not** open the dashboard — run `status` in another terminal or use **Start Engine** after opening the UI. ### 2.1 Extract graph data as JSON (DO NOT grep `.md` files) Use **`read`** with a **positional** `target_type`, then an optional `query` string. | `target_type` | `query` | Use when | |---------------|---------|----------| | `page` | Logseq page title | Full spatial page context | | `subtree` | `Page Title\|block-uuid` or JSON | Token-efficient block extract | | `memory` | (omit) | L1 session memory files | | `bootstrap_status` | (omit) | Graph-local catalog semaphore and informational `read_only` policy | | `shadow_status` | (omit) | Separate content-free external-cache readiness; no initialization | | `dashboard` | (omit) | Vault / daemon overview | | `block_ast` | `Page Title\|block-uuid` | Single block AST excerpt | | `xray_page` | Page title | X-Ray aliases `[0]`…`[n]` for mutations | | `structural_hops` | hop query | Link/tag neighborhood report | `dashboard` ignores `query`. Linux/macOS use a request-owned process group: 1800 seconds execution, then one five-second cleanup deadline. Failure is JSON, not a partial dashboard; inspect `code`, `last_phase` and `cleanup_verified`. Busy requests do not queue. Unverified cleanup blocks new dashboards until operator diagnosis/restart. Windows retains legacy behavior without this cancellation guarantee. See [bounded dashboard reads](docs/quality/DASHBOARD_BOUNDED_READ.md). **Command (canonical):** ```bash export LOGSEQ_GRAPH_PATH="/absolute/path/to/your/logseq/graph" uvx matryca-plumber --json read page "My Project" ``` **Semantic macro (bundled context):** ```bash uvx matryca-plumber context load "My Project" uvx matryca-plumber context load "My Project|aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" ``` **Search (examples):** ```bash uvx matryca-plumber --json search bm25 "redis cache" uvx matryca-plumber --json search journal_tasks "7" ``` Always **parse JSON from stdout** when using `--json`. Never hand-parse raw `pages/*.md` or `journals/*.md`. ### 2.2 MCP (FastMCP **stdio** — NOT HTTP port 8080) MCP is a **stdio** sidecar: the host (Cursor, Claude Desktop, **Hermes Agent**, etc.) spawns `matryca-plumber` and talks JSON-RPC over stdin/stdout. There is **no** `mcp --port` flag in the v1.9 line. **Lazy AST handshake (v1.9.6+):** MCP lifespan defers full-vault AST parsing until the **first graph tool call**. `initialize` + `tools/list` complete in seconds; `read_graph_data` / `target_type=bootstrap_status` and `target_type=memory` do **not** require the AST index. **Requirements:** 1. `LOGSEQ_GRAPH_PATH` set to the vault root. 2. `MATRYCA_MCP_ENABLED=true` (off by default for safety). **Host config pattern (Cursor / Claude Desktop):** ```json { "mcpServers": { "matryca-logseq": { "command": "uvx", "args": ["matryca-plumber"], "env": { "LOGSEQ_GRAPH_PATH": "/absolute/path/to/your/logseq/graph", "MATRYCA_MCP_ENABLED": "true" } } } } ``` With no CLI subcommand and MCP enabled, `uvx matryca-plumber` starts the **stdio** MCP server. For interactive graph work without MCP, prefer the CLI in section 2.1. #### Hermes Agent (`~/.hermes/config.yaml`) Hermes requires the host MCP client extra: `cd ~/.hermes/hermes-agent && uv pip install -e ".[mcp]"`. ```yaml mcp_servers: matryca-plumber: command: uvx args: [matryca-plumber] env: MATRYCA_MCP_ENABLED: "true" LOGSEQ_GRAPH_PATH: /absolute/path/to/vault enabled: true connect_timeout: 120 # handshake (initialize + tools/list) — not vault parse time timeout: 300 # per tool call; first graph tool pays AST load on large vaults ``` | Setting | Purpose | |---------|---------| | `connect_timeout` | Hermes **handshake** only (`initialize`, `tools/list`). **60–120 s** is enough with lazy AST. | | `timeout` | Each **tool invocation**. Raise for large vaults on the **first** graph read/search (AST cold start). Rule of thumb: `(pages + journals) × ~0.2 s` on slow mounts — measure once. | Full guide: `docs/integrations/hermes-agent.md` · stderr telemetry: `AST cache bootstrap started|complete` in `~/.hermes/logs/mcp-stderr.log`. ### 2.3 AX robustness — page titles & write targets (v1.9.7+) Local LLMs often send **wrong page title formats**. Plumber normalizes before lookup: | You may send | Plumber accepts | |--------------|-----------------| | `Domain/Topic` (semantic) | Canonical Logseq title | | `Domain___Topic` or `Domain___Topic.md` | Same (namespace encoding) | | `pages/Domain___Topic.md` | Strips prefix/suffix | | Wrong casing `DOMAIN/topic` | Case-insensitive match | **Never send** path traversal (`../`, `../../etc/passwd`) — rejected with a clear error; MCP session survives. **`mutate_graph` / `write_outline` targets:** | `target` | When to use | |----------|-------------| | `parent-block-uuid` | After `xray_page` or spatial read | | `[n]` | X-Ray alias from `.matryca_xray_state.json` | | `Page Title\|block-uuid` or `Page Title\|[n]` | **Recommended** when the model might hallucinate UUIDs | If the block ref is invalid but the **page exists**, Plumber **safe-appends** at page bottom and returns `warnings` (check them). Bare unknown aliases like `[42]` without a page still fail with `ok: false`. Spec: `docs/openspec/agent-ax-robustness.md` ### 2.4 Security & Sandbox (v1.9.9+) Graph reads and writes stay inside **`LOGSEQ_GRAPH_PATH`**. v1.9.9 adds defense-in-depth beyond MCP title normalization; **v1.9.13 (Enterprise Resilience)** hardens parsing and RAG boundaries — TOCTOU-safe bounded JSON reads, `templates_subdir` traversal rejection, namespace-aware semantic cache keys, subtree heading fences (token-efficient excerpts), and string-aware LLM JSON recovery so braces inside string values do not truncate payloads. **v1.9.14** adds journal-aware Phase 2 clustering (daily notes no longer inflate `[unclustered]` or cluster-focus prompts) and skips entity-consolidation LLM turns for journal/date wikilink pairs. **v1.9.15** bypasses Phase-2 semantic indexing and dual embeddings for `journals/` pages (Phase-1 AST cache, link registry, and OCC `mtime` ledger still run). **v1.10.0** adds flock-protected master catalog I/O (merge-on-save), atomic link registry writes, and harvest catalog/page parity on OCC abort. **v1.10.3** tightens flock sidecar file mode to `0o600`, offloads Sovereign UI config saves from the HTTP event loop, and enforces strict Pydantic LLM/outline contracts (`extra="forbid"`, recursive OpenAI strict JSON schemas). **v1.10.5** raises **`logseq-matryca-parser`** to **1.3.1** (YAML frontmatter, case-insensitive graph routing, asset extraction, root public API exports). **v1.10.6** unifies page RMW and JSON sidecar flock via `platform_lock.py` (NB acquire + backoff + reentrancy, #40) and adds OCC-safe hub page compiles for Master Index / Graph Insights (#34). **v1.11.1** pins parser **1.4.0**. **v1.11.2** inverts graph→daemon post-write coupling via `graph.post_write` port (#134), bounds generational/BM25 and block-vector RAM with LRU env caps, and uses `st_mtime_ns` OCC on page writes (#153 partial). | Control | Operator note | |---------|----------------| | Path sandbox | `read_graph_file_text()` on graph paths; `../` and symlink escape → `PathTraversalSecurityError` | | Link registry | Tampered `.matryca_link_registry.json` paths are rejected before read | | JSON size cap | `MATRYCA_JSON_MAX_BYTES` (default 64 MiB) on catalog/registry/daemon/cache loaders | | Memory LRU | `MATRYCA_GENERATIONAL_CACHE_MAX_GRAPHS` (default 4); `MATRYCA_BLOCK_VECTOR_STORE_MODE=ondemand` (default); `MATRYCA_BLOCK_VECTOR_STORE_MAX_GRAPHS` (default 4) — see `.env.example` Advanced section | | UI token | Set `MATRYCA_UI_TOKEN` on shared hosts; `.env.example` templates `MATRYCA_UI_REQUIRE_EXPLICIT_TOKEN=true` | | Debug NDJSON | `MATRYCA_LLM_DEBUG_LOG_PATH` must lie under allowed roots; secrets redacted when enabled | **Do not** rely on raw filesystem reads of `pages/` — use Plumber tools (section 2.1). Full matrix: `SECURITY.md` · spec: `docs/openspec/security-sandbox.md` ### 2.5 Diagnostics & audit (no `doctor` command) There is **no** `doctor` subcommand. Use these instead: | Goal | Command | |------|---------| | Bootstrap / graph insights dashboard | `uvx matryca-plumber plumber audit` or `uvx matryca-plumber audit` | | Semantic cluster neighborhoods | `uvx matryca-plumber plumber cluster` or `uvx matryca-plumber cluster` | | Sovereign UI + pre-flight checks | `uvx matryca-plumber status` → UI on `http://127.0.0.1:8500` (no daemon until **Start Engine** or `plumber start`) | | Block-reference lint | `uvx matryca-plumber lint block_refs` | | Maintenance daemon (headless) | `uvx matryca-plumber plumber start` / `plumber stop` (no browser; pair with `status` for the cockpit) | **JSON audit output:** ```bash export LOGSEQ_GRAPH_PATH="/absolute/path/to/your/logseq/graph" uvx matryca-plumber --json plumber audit ``` ### 2.6 Shadow DB and Strict Read Only (v2.0.0 stable contract) Shadow DB is a **derived read cache outside `LOGSEQ_GRAPH_PATH`**. It does **not** replace Markdown on disk. In v2.0.0 it is **default-on**; an explicit false value is the emergency opt-out. Strict Read Only permits only validated external derived-cache writes and always protects the graph root. `read bootstrap_status` describes the graph-local catalog and its checkpoint, not Shadow readiness. Its informational `read_only` flag selects read-only guidance; missing-checkpoint 0/0 is not a Shadow indexing count. In Strict Read Only, starting the observer cannot create a missing Master Index/catalog. Use `read shadow_status` separately; it performs no cache initialization. Do not recommend graph-local bootstrap or Cloud Indexing under this policy. | Env var | Default | When `true` | |---------|---------|-------------| | `MATRYCA_READ_ONLY` | `false` | Blocks every Matryca write, lock, temp file, or support artifact inside the Logseq graph; reads remain available | | `MATRYCA_SHADOW_DB_ENABLED` | `true` | Maintains the external cache; `search_graph(bm25)` prefers FTS5 and `read_graph_data(subtree)` prefers recursive CTE only while `READY`; **always falls back** to generational BM25 / parser+AST when disabled or non-ready | | `MATRYCA_MEMORY_GRAPH_ENABLED` | `false` | Enables the P0 `search_graph(recall)` envelope only. It is provider-free and graph-immutable: disabled, stale, empty-unproven, unavailable, or unsupported-filter requests return an explicit structured state and never fall back, rebuild, write, or call a model. | | `MATRYCA_SHADOW_QUARANTINE_ENABLED` | `true` | Park over-budget pages instead of failing the whole rebuild (beta.1); `false` restores strict mode | | `MATRYCA_SHADOW_WRITER_LOCK_TIMEOUT_S` | `10` | Cross-process advisory flock wait for incremental sync/delete (alpha.1) | | `MATRYCA_SHADOW_REBUILD_LOCK_TIMEOUT_S` | `120` | Cross-process advisory flock wait for full rebuild (alpha.1) | | `MATRYCA_SHADOW_DB_BUSY_TIMEOUT_MS` | `5000` | SQLite `busy_timeout` for shadow writers (clamped 0–60000 ms; alpha.1) | **Operator health (no `doctor`):** Sovereign UI `status` → sidebar **Shadow DB** row (sourced from `GET /api/state.shadow_db`: `state`, `last_full_sync_at`, `source_page_count`, `indexed_page_count`, `lag_pages`, `last_sync_error`, `not_ready_reason`, `quarantined_page_count`). `not_ready_reason` is a closed vocabulary of content-free codes explaining why the cache is not accelerating reads: `not_bootstrapped`, `bootstrap_in_progress`, `database_unreadable`, `schema_version_mismatch`, `sync_error`, `full_sync_incomplete`, `page_count_mismatch`, `cache_unavailable`. It is `null` when the state is `ready` or `disabled`. Treat an unrecognised code as `null` — the vocabulary may grow. `full_sync_incomplete` is the code an agent will most often see on a real vault; see below. **Independent authority:** Read Only governs the vault boundary; Shadow governs only the external derived cache. Read Only + Shadow enabled is the recommended protected-reading profile. Shadow never authorizes a graph write, and a cache failure never blocks Markdown/BM25 reads. **Over-budget pages are quarantined, not fatal.** A page whose parse exceeds `MATRYCA_PAGE_PARSE_TIMEOUT_S` (default **15 s**, clamped 2–120 s) is parked in `quarantined_pages` and left out of the cache; the rest of the graph is indexed normally and health stays `READY` under the invariant `indexed + quarantined == source == actual`. Reads for a parked page route to Markdown, which is authoritative either way. A page is released automatically as soon as it parses within budget. `GET /api/state.shadow_db.quarantined_page_count` reports how many are parked; they are excluded from `lag_pages` because they are a settled decision, not pending work. `MATRYCA_SHADOW_QUARANTINE_ENABLED=false` restores the strict pre-2.0 behaviour where any over-budget page aborts the rebuild. Measured on a daily-use vault of 1,014 graph pages: **3 pages (0.30%) exceed the default**, consuming the large majority of total parse time. A filesystem sweep of the same vault counts 25 over-budget files out of 3,378, but 22 of those are Logseq's own version history and backups, which the cache never reads. Parse cost is bimodal (nothing between 5 s and 40 s) and **uncorrelated with page size** — the largest page in that corpus (650,106 B) parses in 0.54 s while a 336,260 B page does not finish within 115 s under load. **What an agent should conclude:** a non-zero `quarantined_page_count` is expected on a large vault and is **not** corruption, not an error, and not a reason to retry, rebuild repeatedly, or modify vault content. Do not "fix" it by editing or splitting user pages. Reads for those pages are correct via the Markdown/BM25 fallback; they simply get no FTS or subtree acceleration. Raising `MATRYCA_PAGE_PARSE_TIMEOUT_S` reduces the count at the cost of much slower rebuilds. Analysis: `docs/quality/SHADOW_DB_PARSE_BUDGET_TRIZ_2026-07-27.md`. Roadmap: `docs/roadmaps/ROADMAP_V2_PREPARATION.md` · Epic [#20](https://github.com/MarcoPorcellato/matryca-plumber/issues/20). --- ## 3. Zero-shot examples (small LLMs — copy exactly) **A. Help + env check** ```bash export LOGSEQ_GRAPH_PATH="$HOME/Logseq/graphs/MyGraph" uvx matryca-plumber --help ``` **B. Read one page as JSON** ```bash export LOGSEQ_GRAPH_PATH="$HOME/Logseq/graphs/MyGraph" uvx matryca-plumber --json read page "My Project" ``` **C. Recent journal tasks (last 7 days) as JSON** ```bash export LOGSEQ_GRAPH_PATH="$HOME/Logseq/graphs/MyGraph" uvx matryca-plumber --json search journal_tasks "7" ``` **D. Run graph audit after user reports errors** ```bash export LOGSEQ_GRAPH_PATH="$HOME/Logseq/graphs/MyGraph" uvx matryca-plumber --json plumber audit ``` **E. Load bundled agent context (markdown stdout)** ```bash export LOGSEQ_GRAPH_PATH="$HOME/Logseq/graphs/MyGraph" uvx matryca-plumber context load "My Project" ``` **F. Write outline with page context (safe fallback if UUID wrong)** ```bash export LOGSEQ_GRAPH_PATH="$HOME/Logseq/graphs/MyGraph" uvx matryca-plumber --json mutate write_outline \ --target "My Project|aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" \ --payload '{"text":"New bullet","children":[]}' ``` **G. Tana workspace JSON import (dry-run default — add `--apply` to commit)** ```bash export LOGSEQ_GRAPH_PATH="$HOME/Logseq/graphs/MyGraph" uvx matryca-plumber --json import tana --file "$HOME/Downloads/tana-workspace.json" uvx matryca-plumber import tana --file "$HOME/Downloads/tana-workspace.json" --apply ``` **H. Inject a native Logseq advanced-query block (open TODO/LATER/WAITING dashboard)** ```bash export LOGSEQ_GRAPH_PATH="$HOME/Logseq/graphs/MyGraph" uvx matryca-plumber --json mutate inject_query \ --target "My Project|parent-block-uuid" \ --payload '{"query_preset": "open_markers", "dry_run": true}' ``` Presets: `open_markers` (open TODO/LATER/WAITING), `pages_tagged` (needs a `"tag"` field). Or pass raw `"query_edn"` instead of `query_preset`. Always `dry_run: true` first. **I. Preview hashtag/tag-variant unification (e.g. `#AI` vs `#ai`)** ```bash export LOGSEQ_GRAPH_PATH="$HOME/Logseq/graphs/MyGraph" uvx matryca-plumber --json lint unify_tags ``` Preview-only: returns clustered tag variants and suggested canonical form. Applying rewrites vault-wide requires explicit operator consent — this command never writes. **J. Generate a Map-of-Content index page for a namespace** ```bash export LOGSEQ_GRAPH_PATH="$HOME/Logseq/graphs/MyGraph" uvx matryca-plumber --json mutate generate_moc \ --target "Project/Sub" \ --payload '{"dry_run": true}' ``` Writes `MOC Project/Sub` (or `output_page_title`) listing every page under that namespace as grouped `[[wikilinks]]`. Always `dry_run: true` first. For **today's journal page** as `read page`, use the **exact Logseq page title** shown in the app (locale-dependent), not a file path like `journals/2026_06_05.md`. --- ## 4. Anti-patterns (DO NOT DO THIS) * **DO NOT** `grep`, `find`, or write Python to parse `pages/` / `journals/` — use `uvx matryca-plumber read` / `search` / `context load`. * **DO NOT** `git clone https://github.com/MarcoPorcellato/matryca-plumber` to "use" the tool — use **`uvx matryca-plumber`** from PyPI. * **DO NOT** `pip install matryca-plumber` unless the user explicitly asked for a global install. * **DO NOT** invent flags: no `--graph`, no `doctor`, no `mcp --port 8080`. * **DO NOT** ask the user to install Python dependencies manually — **`uvx`** resolves the wheel. * **DO NOT** hand-craft `pages/*.md` filenames with raw `/` — pass **semantic titles** (`Domain/Topic`); Plumber maps to `Domain___Topic.md`. * **DO NOT** panic on `warnings` in mutate JSON — read them; Plumber may have recovered via safe append. --- ## 5. Further reading (humans & agents) * Operator README: `README.md` * Agent onboarding spec: `docs/openspec/agent-onboarding.md` * **AX robustness spec:** `docs/openspec/agent-ax-robustness.md` * LLM OS contract (two-tier, Soft Gate, Safe-Sync): `SYSTEM_PROMPT.md` § "LLM OS" * Agent DX spec (CLI JSON, Journey Log — one cumulative `- 🤖 Matryca Activity` bullet per day in the daemon journal): `docs/openspec/agent-dx.md` * Security (MCP gate, graph sandbox, bounded JSON, CLI redaction): `SECURITY.md` · `docs/openspec/security-sandbox.md` * Hermes Agent MCP (lazy handshake, timeouts): `docs/integrations/hermes-agent.md` * Tana workspace JSON import (`import_tana`, dry-run default): `docs/openspec/tana-import.md` ### Contributing to this repository (not the user vault) **PyPI `uvx` usage (sections 0–2) is for operating on the user's Logseq graph.** To **patch Matryca Plumber itself**, clone/fork this repo, read `CONTRIBUTING.md`, and run `make check` before opening a PR. **Good first issues (scoped fixes, existing tests):** https://github.com/MarcoPorcellato/matryca-plumber/issues?q=is%3Aopen+label%3A%22good+first+issue%22 | Issue | Difficulty | Scope | |-------|------------|-------| | [#45](https://github.com/MarcoPorcellato/matryca-plumber/issues/45) | 2/10 | OCC `file_mtime_drifted` in link verification | | [#85](https://github.com/MarcoPorcellato/matryca-plumber/issues/85) | 2/10 | `BootstrapHarvestStatus` Literal dedup (slice of #62) | | [#53](https://github.com/MarcoPorcellato/matryca-plumber/issues/53) | 3/10 | Dedup page read in Phase-2 cognitive lint | | [#56](https://github.com/MarcoPorcellato/matryca-plumber/issues/56) | 3/10 | Defer mmap decode on regex harvest path | | [#69](https://github.com/MarcoPorcellato/matryca-plumber/issues/69) | 3/10 | Skip cluster-focus for singleton clusters | | [#71](https://github.com/MarcoPorcellato/matryca-plumber/issues/71) | 4/10 | Centralize journal page detection in graph layer | Maintainer blueprints (verify commands, welcome-comment text): `good_first_issues_blueprints.md`. When suggesting a contribution task, **pick from the table above** — do not implement these on the user's behalf unless they explicitly assign one. --- ## 6. LLM OS — two-tier architecture (MANDATORY for graph work) Matryca Plumber implements a **dual-LLM** system. You are almost certainly **Tier 2 (Cognitive Agent)** — not the background Gardener. | Tier | Role | Your action | |------|------|-------------| | **Tier 1 — Gardener** | Daemon Phase 1 harvest (`matryca plumber start`) | **NEVER impersonate.** Do not run harvest, rewrite `### Matryca Semantic Index` blocks, or edit `master_catalog.json`. | | **Tier 2 — Cognitive Agent** | You (MCP / CLI) | **MUST** follow the Master Index Soft Gate and Safe-Sync rules in [`SYSTEM_PROMPT.md`](SYSTEM_PROMPT.md) § "LLM OS". | **Before any `search_graph` or targeted `read_graph_data` on L2 wiki pages:** 1. `read_graph_data` / `target_type=memory` — load L1 session rules. 2. `read_graph_data` / `target_type=bootstrap_status` — check graph-local catalog state and `read_only`. 3. When the Master Index is present, use `target_type=page` / `query=Matryca Master Index` to read the compiled catalog. 4. If the index is **missing**, **empty**, or Phase 1 is **in progress**, explain the state. In writable mode, present Local Daemon / Blind Search / Cloud Indexing and **WAIT** for explicit authorization before Blind Search or Cloud Indexing. With `read_only=true`, do not offer graph-writing bootstrap/indexing; query `shadow_status` separately and stay within authorized targeted reads. Uncatalogued discovery still requires explicit authorization. **NEVER** guess page titles or `grep pages/` without authorization. 5. When the gate is green (or user authorizes Option B), pinpoint exact `[[Page Title]]` from the index, then call narrow reads (`page`, `subtree`, `xray_page`). **CLI equivalent:** ```bash uvx matryca-plumber --json read bootstrap_status uvx matryca-plumber --json read page "Matryca Master Index" ``` **Safe-Sync (summary):** READ only via Matryca tools on `pages/` + `journals/` under `LOGSEQ_GRAPH_PATH`. **NEVER** open Logseq's internal app database. WRITE only via `mutate_graph`, `refactor_blocks`, `ingest_document`, `import_tana`, `store_fact` (atomic `.md` + OCC). **`import_tana` dry-run default.** Full contract: `SYSTEM_PROMPT.md`.