Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,33 @@ Entries that change an on-disk format or a response shape say so.
## [Unreleased]

### Added
- Both core SDKs gain the rest of the schema surface:
`put_schema`/`putSchema`, `audit_schema`/`auditSchema`, and
`validate_schema`/`validateSchema`, alongside the existing
`get_schema`/`getSchema` — closing the parity gap with HTTP and MCP,
which already exposed all four; an SDK-only integration previously
had to drop to raw HTTP to install, audit, or dry-run a schema.
`audit`/`validate` decode the shared `SchemaAudit` shape
(`{total, violations: [{association, issues}], untyped_concepts,
undeclared_types, unknown_labels, reserved_alias_conflicts}`,
ADR 0009 §10) with `violations` paging like every other match list;
Python's `put_schema`/`validate_schema` accept either a plain mapping
or the decoded `SchemaDocument` dataclass. Recorded in
`sdk/spec/surface.yaml` like every other cross-language method.
- `POST /contexts/{name}/unreachable_from` joins ADR 0009 §6.3's
traversal exclusion, amending #381's three-exclusion list: once a
schema document is installed, `schema:type` edges are invisible to
the coverage audit — never a bridge in the reachability walk (a
shared type name would otherwise put every typed instance in one
reachable component and silently under-report genuine orphans, the
one failure mode this audit exists to catch) and never reported as
orphans themselves, the same "never reported, never a bridge"
contract `explore_excluding` documents. Backed by the new additive
`Context::unreachable_from_excluding` (the same
monomorphized-`visible`-closure pattern as `explore_excluding`, so
the unfiltered path pays nothing); gated, like every §6.3 exclusion,
on document existence alone, never `mode` — a schema-free context
answers byte-identically to before.
- Schema metrics and a documentation reference page (#388, S10 of
#218's ADR 0009 split §15) — closing the split: strict/warn's actual
effect was previously invisible on `/metrics`, and the feature had no
Expand Down Expand Up @@ -618,6 +645,24 @@ Entries that change an on-disk format or a response shape say so.
host application's call.

### Changed
- **Breaking (SDKs):** `add_associations`/`addAssociations` returns
`AddAssociationsResult {applied, issues, schema_violations}` instead
of the bare applied count, and `BatchApplyResult`/`ImportResult` gain
`issues`/`schema_violations` fields (`ImportResult` also `schemas`,
one `SchemaImportOutcome` per `taguru_schema` record the stream
restored). Both SDKs previously unwrapped only the envelope's
`result`, which made ADR 0009 §8.3's `warn`-mode carrier — the
`issues`/`schema_violations` fields riding *beside* `result` on a
write whose associations violated the schema — unreachable through
the SDK by any means: a `strict` refusal's issues survive in the
error body, but flipping a context to `warn` silently hid the same
violations from SDK callers, the exact asymmetry §8.3's "identical
`Issue` values in both modes" contract exists to prevent. Migration:
`applied = ctx.add_associations(ops)` becomes
`ctx.add_associations(ops).applied`; a caller that ignored the
return value is unaffected, and every new field is empty/zero for
`off` mode, no schema, a conforming write, or a server predating the
fields.
- `ManifestEntry`/`CheckpointFingerprint` (Rust) and their SDK
checkpoint-fingerprint twins gain a `schema_digest` field (#386, S8 of
#218's ADR 0009 split §11), so that swapping in a different schema
Expand Down Expand Up @@ -660,6 +705,28 @@ Entries that change an on-disk format or a response shape say so.
`events_path`); `isinstance`/attribute access and every field #351/#352
already published are unaffected.

### Fixed
- Documentation drift, in the live protocol manual first: the document
`GET /protocol` and every MCP `initialize.instructions` actually
serve (`src/llm-protocol.md`) had no route-table rows for
`GET/PUT /contexts/{name}/schema`,
`POST /contexts/{name}/schema/audit`,
`POST /contexts/{name}/schema/validate`, or the pre-existing
`POST /contexts/{name}/drift/audit`, no `schema_mode` in
`GET /contexts`' documented row shape, and no `no_schema` in the
stable error-`code` vocabulary — all three already shipped and
fixture-pinned. All added; `docs/schema.html` now also names the
directory row's `schema_mode` and the SDK schema methods, and its
§6.3 exclusion list includes the coverage audit. Env-var docs catch
up too: `docs/getting-started.html`'s table gains
`TAGURU_PASSAGES_WAL_MAX_BYTES`, `TAGURU_AUTH_FAIL_LIMIT_PER_MIN`,
`TAGURU_CROSS_SEARCH_CONCURRENCY`, and `TAGURU_EMBED_PARALLEL`, and
README's MCP section documents `TAGURU_MCP_MAX_CONCURRENT_TOOLS`
and `TAGURU_MCP_MAX_RESULT_BYTES` — previously in `taguru --help`
and `KNOWN_KEYS` only. One stale mirror comment
(`sdk/python-langchain/.../_extract.py`, "PROMPT_VERSION 2" over a
`PROMPT_VERSION = 3` constant) now matches its TypeScript twin.

## [0.6.0] - 2026-08-01

### Added
Expand Down
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,10 @@ round trip, request by request, is traced in the
[walkthrough](https://t0k0sh1.github.io/taguru/mcp-rag-walkthrough.html).

`taguru-mcp` also honors `TAGURU_MCP_TIMEOUT_SECS` (per-request budget
against the server, default 75 — raise it for a slow local model) and
`TAGURU_MCP_MAX_LINE_BYTES` (stdio frame cap).
against the server, default 75 — raise it for a slow local model),
`TAGURU_MCP_MAX_LINE_BYTES` (stdio frame cap), and
`TAGURU_MCP_MAX_CONCURRENT_TOOLS` (simultaneously in-flight tool
calls, default 8).

The same tools are also served remotely: `POST /mcp` speaks the MCP
Streamable HTTP transport (stateless profile — plain JSON responses,
Expand All @@ -168,6 +170,11 @@ claude mcp add --transport http taguru https://your-host/mcp \
# name: "taguru", authorization_token: "…"}]
```

On the server side, `TAGURU_MCP_MAX_RESULT_BYTES` (default 8 MiB) caps
how much of one tool's result `POST /mcp` will buffer — past it the
call fails naming the export escape hatches instead of buffering
forever.

claude.ai custom connectors (web and mobile) authenticate with OAuth
instead of a pasted header: set `TAGURU_PUBLIC_URL`, point the
connector at `https://your-host/mcp`, and approve the consent page by
Expand Down
4 changes: 4 additions & 0 deletions docs/getting-started.html
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ <h3>Key environment variables</h3>
<tr><td>TAGURU_FLUSH_SECS</td><td>5</td><td>Image flush interval. With the WAL on, this is freshness cadence, not a loss window</td></tr>
<tr><td>TAGURU_WAL</td><td>on</td><td>fsync every acknowledged write before applying it (a crash loses nothing). <code>0</code> restores the flush-interval loss window</td></tr>
<tr><td>TAGURU_WAL_MAX_BYTES</td><td>256 MiB</td><td>Per-context WAL ceiling. Only approached when flushes keep failing; past it, writes are refused with 500</td></tr>
<tr><td>TAGURU_PASSAGES_WAL_MAX_BYTES</td><td>1 GiB</td><td>Passage-log backstop, the sibling ceiling for the passage lane — engages only when compaction is stuck; <code>0</code> disables</td></tr>
<tr><td>TAGURU_REPLICATE_URL</td><td>—</td><td>Object-storage bucket (<code>s3://</code> / <code>gs://</code> / <code>az://</code> / <code>file://</code>) for continuous replication of the whole data directory, epoch-fenced; credentials via each cloud's default chain. Restore with <code>taguru restore</code> — or start a server on an empty directory with the same URL and it boots straight from the bucket (pinned contexts hydrate before the port opens, the rest on first touch). Unset = off</td></tr>
<tr><td>TAGURU_REPLICATE_INTERVAL_MS</td><td>1000</td><td>Replication poll cadence — the steady-state RPO knob; per-lane lag is exported at <code>/metrics</code></td></tr>
<tr><td>TAGURU_TAKEOVER</td><td>off</td><td><code>1</code> (or <code>serve --take-over</code>) acknowledges deposing the bucket's newest writer while it still looks alive (heartbeat within 300s, no clean stop). A cleanly stopped writer never needs it; starting a writer against a bucket IS the promotion act</td></tr>
Expand All @@ -131,14 +132,17 @@ <h3>Key environment variables</h3>
<tr><td>TAGURU_EMBED_URL / _MODEL / _API_KEY</td><td>—</td><td>Semantic entry tier (OpenAI-compatible <code>/embeddings</code>). Unset keeps the entrance purely lexical</td></tr>
<tr><td>TAGURU_EMBED_TIMEOUT_SECS</td><td>60</td><td>Per-attempt ceiling for one embedding provider round trip; a request's remaining budget bounds an attempt further. Three consecutive failed attempts open a <a href="architecture.html#search">circuit breaker</a> — fast-fails for 30s, then one probe decides whether to close it</td></tr>
<tr><td>TAGURU_EMBED_AUTO</td><td>off</td><td>Re-embed only the changes on each flush. Recommended whenever agents drive the ingest (don't count on refresh being called)</td></tr>
<tr><td>TAGURU_EMBED_PARALLEL</td><td>1</td><td>Concurrent 128-item chunk dispatch for one context's gloss/passage embedding refresh (<code>1</code> = sequential). Raise to match the provider's rate limit, not the core count; concurrent refreshes across contexts aren't serialized and multiply it</td></tr>
<tr><td>TAGURU_EMBED_PASSAGES</td><td>off</td><td>Also embed paragraphs = the semantic side of the text lane. A corpus is orders of magnitude larger than its glosses, so the spend is opt-in</td></tr>
<tr><td>TAGURU_PASSAGE_VECTOR_LIMIT</td><td>20,000</td><td>Ceiling on paragraph vectors held per context. Past it the lexical lane still serves every paragraph; only the semantic side goes partial (the refresh response reports the skips). The default is pinned above the <a href="architecture.html#search">approximate-search threshold</a> (10,000, compiled in) by a compile-time assertion, so default configuration always has headroom to engage the index — a custom value set below the threshold isn't blocked, only logged once at boot</td></tr>
<tr><td>TAGURU_SEMANTIC_FLOOR</td><td>0.35</td><td>Floor for the semantic entry tier. <b>A property of the embedding model</b> (default calibrated for text-embedding-3-large; ~0.2 for <a href="bedrock.html">Bedrock</a>'s Titan V2) — <code>taguru calibrate</code> <a href="bedrock.html#floor">measures the right value</a></td></tr>
<tr><td>TAGURU_PUBLIC_URL</td><td>—</td><td>Public base URL. Setting it enables OAuth on remote MCP (<code>/mcp</code>), which lets claude.ai custom connectors attach</td></tr>
<tr><td>TAGURU_RATE_LIMIT_PER_MIN</td><td>0 (off)</td><td>Per-key request budget per minute. Enable it before leaving localhost</td></tr>
<tr><td>TAGURU_AUTH_FAIL_LIMIT_PER_MIN</td><td>10</td><td>Failed-auth attempts per source IP before 429 — the brute-force brake. <code>0</code> disables; coarse behind a proxy (one IP for everyone)</td></tr>
<tr><td>TAGURU_REQUEST_TIMEOUT_SECS</td><td>30</td><td>Time budget per request. Raise to 60+ once an embedding provider is configured</td></tr>
<tr><td>TAGURU_MAX_CONCURRENT_REQUESTS</td><td>256</td><td>Global in-flight ceiling. Excess requests are shed immediately with 503 + <code>Retry-After</code>; <code>0</code> disables</td></tr>
<tr><td>TAGURU_MAX_CONCURRENT_HEAVY_OPS</td><td>2</td><td>Shared ceiling for vocabulary audits and context compactions. Excess calls are shed immediately with 503 + <code>Retry-After</code>; <code>0</code> disables</td></tr>
<tr><td>TAGURU_CROSS_SEARCH_CONCURRENCY</td><td>4</td><td>Member contexts searched in parallel by a single cross-context (group) recall/query/passage search</td></tr>
<tr><td>TAGURU_AUTO_COMPACT</td><td>on</td><td>Ratio-triggered auto-compaction: each flush tick rebuilds at most the one worst context whose dead ratio exceeds <code>TAGURU_AUTO_COMPACT_RATIO</code> (0.5 — dead weight outgrew live content), behind the heavy-ops ceiling above. <code>0</code> keeps compaction manual-only</td></tr>
<tr><td>TAGURU_CONTEXT_QUOTAS</td><td>—</td><td>Per-context ceilings as one JSON object, <code>{"sake": {"storage_bytes": …, "cache_bytes": …}}</code> — each field optional, never both absent. <code>storage_bytes</code> refuses growth writes at the ceiling with 507 <code>storage_full</code> (retract, compact, and delete stay open — they are the ways back under); <code>cache_bytes</code> bounds the context's resident share, evicting the over-share context first under cache pressure. Declared quotas surface as <code>taguru_context_quota_bytes</code> next to the per-context usage gauges. A broken declaration refuses boot, like broken credentials</td></tr>
</tbody>
Expand Down
21 changes: 16 additions & 5 deletions docs/schema.html
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,10 @@ <h2>The reserved <code>schema:type</code> label</h2>
<code>relations</code> declares an entry named <code>schema:type</code>.</li>
</ol>
<p>
And three exclusions keep it out of surfaces that were never meant to see it: it is never
traversed by <code>activate</code>/<code>explore</code>, it never appears in the extraction
And a set of exclusions keeps it out of surfaces that were never meant to see it: it is never
traversed by <code>activate</code>/<code>explore</code> or by
<code>unreachable_from</code>'s coverage audit (where a shared type name would otherwise
bridge disconnected facts and hide genuine orphans), it never appears in the extraction
vocabulary block or <code>list_labels</code>'s default page, and type-name concepts are
excluded from <code>audit_vocabulary</code>'s twin sweep once a schema exists. The single
gate for all of this is "an installed schema document exists," never "<code>mode !=
Expand Down Expand Up @@ -255,9 +257,18 @@ <h2>HTTP and MCP surface</h2>
</p>
<p>
The MCP tools <code>get_schema</code>, <code>put_schema</code>, <code>validate_schema</code>,
and <code>audit_schema</code> round-trip onto these same four routes; <code>add_associations</code>
and <code>import</code> inherit write-time enforcement for free, since MCP is a pure mapping
onto the HTTP surface.
and <code>audit_schema</code> round-trip onto these same four routes, as do the Python and
TypeScript SDKs' <code>get_schema</code>/<code>put_schema</code>/<code>validate_schema</code>/
<code>audit_schema</code> (<code>getSchema</code>/<code>putSchema</code>/… in TypeScript);
<code>add_associations</code> and <code>import</code> inherit write-time enforcement for free,
since MCP is a pure mapping onto the HTTP surface.
</p>
<p>
For routing without a second call, <code>GET /contexts</code>'s directory rows also carry a
read-only <code>schema_mode</code> — the installed document's own <code>mode</code>, or
<code>null</code> for a context that never installed one (never a bare <code>off</code>
standing in for "no document", the same distinction <code>GET /schema</code>'s own 404
draws).
</p>
</section>

Expand Down
2 changes: 1 addition & 1 deletion sdk/python-langchain/src/taguru_langchain/_extract.py
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ def corrective_message(parse_error: str, length_limited: bool, fact_budget: int)
)


# -- the prompt (mirrors extract.rs system_prompt, PROMPT_VERSION 2) -------------
# -- the prompt (mirrors extract.rs system_prompt, PROMPT_VERSION 3) -------------


def system_prompt(
Expand Down
14 changes: 14 additions & 0 deletions sdk/python/src/taguru/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,13 @@
from ._models import (
Activation,
ActivationPage,
AddAssociationsResult,
AliasEntry,
AliasPage,
Association,
Attribution,
AuditAliases,
AuditNames,
BatchApplyResult,
Bm25Explain,
BudgetLimits,
Expand Down Expand Up @@ -79,6 +82,7 @@
GroupPage,
ImportOutcome,
ImportResult,
Issue,
LabelPage,
LabelUsage,
LaneEvidence,
Expand Down Expand Up @@ -107,7 +111,10 @@
RetractAssociationOutcome,
RetractOutcome,
RetrievalResult,
SchemaAudit,
SchemaDocument,
SchemaImportOutcome,
SchemaViolation,
SearchContextPlan,
SearchExplanation,
SearchLanesPlan,
Expand Down Expand Up @@ -189,10 +196,13 @@
# models
"Activation",
"ActivationPage",
"AddAssociationsResult",
"AliasEntry",
"AliasPage",
"Association",
"Attribution",
"AuditAliases",
"AuditNames",
"BatchApplyResult",
"Bm25Explain",
"BudgetLimits",
Expand Down Expand Up @@ -229,6 +239,7 @@
"GroupPage",
"ImportOutcome",
"ImportResult",
"Issue",
"LabelPage",
"LabelUsage",
"LaneEvidence",
Expand Down Expand Up @@ -257,7 +268,10 @@
"RetractAssociationOutcome",
"RetractOutcome",
"RetrievalResult",
"SchemaAudit",
"SchemaDocument",
"SchemaImportOutcome",
"SchemaViolation",
"SearchContextPlan",
"SearchExplanation",
"SearchLanesPlan",
Expand Down
Loading