---
name: teleo-kb-bridge
description: Use the VPS Postgres KB bridge before answering questions about claims, evidence, edges, schema-backed soul/context, KB approval, or KB edit workflow.
version: 1.0.0
author: m3taversal
license: MIT
metadata:
  hermes:
    tags: [teleo, kb, postgres, claims, evidence, governance]
    related_skills: [leo-synthesis-methods]
---

# Teleo KB Bridge

The canonical Teleo knowledge base is Postgres, not runtime memory.

## Mandatory Default Reply Contract

This contract applies even when the operator asks a broad, multi-part question.
Unless the operator explicitly asks for a detailed audit or long-form document,
draft to at most 170 words and never exceed 220 words. If the operator gives a
smaller limit, that smaller word or line limit is mandatory. Silently shorten
the draft before sending it; never explain that it was shortened.

Use only this compact shape:

1. direct answer in the first sentence;
2. no more than three short bullets containing only the relevant live readback,
   canonical-versus-staged boundary, and current-schema constraint;
3. one proof-changing next action when an action is relevant.

Do not mirror this skill, enumerate every schema field, repeat the answer in a
summary, add a second follow-up, or turn a direct operator question into an
architecture lecture. A question with several requested dimensions still gets
one compressed answer. Load and apply only the rules relevant to that question.
When exact fields are requested, list only the fields needed to establish the
boundary and omit general background. Count before sending; never send more
than 220 words.

## Mandatory Current-Truth Gates

Apply these gates before drafting the answer or proposing a next action:

1. **Proposal readiness:** `approved` is intent approval, not applyability.
   Read the proposal's `readiness` object from `list-proposals`,
   `search-proposals`, or `show-proposal`. If `review_state` is
   `approved_needs_apply_payload`, the next action is normalize into a strict
   payload and review that new packet; never tell the operator to apply the
   legacy row. `approved_contract_present` still proves only contract presence,
   not strict validation, production-worker enablement, authorization, or apply.
2. **Source/evidence audit:** `teleo-kb search` and `teleo-kb context` emit the
   selected claims, evidence, edges, and a deterministic retrieval receipt. Read
   each evidence row's `artifact_verification` before describing provenance.
   Never infer that an artifact is missing from a raw `storage_path`; use the
   reported status. `no_source_pointer` means the canonical source row has no
   resolvable locator, while `missing`, `hash_mismatch`, and `verified` describe
   distinct artifact states. An existing claim-evidence link remains canonical
   evidence when raw-artifact verification is unavailable. A proposal's null
   `applied_at` proves only that proposal did not apply; it does not prove matching
   canonical rows were never written elsewhere.
3. **Shared facts versus agent positions:** store the factual claim once with
   shared evidence. Current agent-owned positions live in `public.beliefs` with
   `id`, `agent_id`, `level`, `statement`, `confidence`, `falsifier`, `rank`,
   `status`, `created_at`, and `updated_at`. The current table has no claim-ID
   foreign key, so exact machine-readable belief-to-claim attribution is a
   schema gap, and there is no belief-edge table. `public.claim_edges` connects
   claims, never belief rows. `reasoning_tools` are methods and
   `behavioral_rules` are operating rules; neither is generic stance storage.
4. **Write and capability boundary:** extraction creates candidates inside the
   reviewed proposal payload, not canonical `public.sources` or `public.claims`.
   Capture a retained artifact, URL/storage path, and content hash; a chat label
   or `source_ref` is not source identity. `teleo-kb prepare-source` is shipped
   on the VPS for a text-like artifact under the private
   `state/kb-source-inbox` root or supplied strict UTF-8
   extraction. It retrieves canonical candidates, asks the model to select
   dense numbered non-empty source fragments, resolves those IDs to byte-exact text, and rejects
   unknown IDs instead of fuzzy-matching. It emits an exact-quote private
   manifest without a DB write. `teleo-kb propose-source` can stage one
   deterministic `pending_review` packet without apply authorization. Automatic
   Telegram attachment capture and arbitrary tweet fetching are not shipped.
   Current `approve_claim` cannot insert
   `behavioral_rules`/`governance_gates`, update beliefs, or update an existing
   claim. Keep unsupported changes out of runnable apply sequences.
   `applied_at` belongs to the proposal receipt, not each inserted row.
5. **Identity and proof:** canonical identity can include `personas`,
   `strategies`, `beliefs`, strategy nodes/anchors, and related governed rows;
   do not reduce it to `public.claims`. No active general DB-to-`SOUL.md`
   renderer automation is currently proven. Unchanged table totals also do not
   prove unchanged rows: updates and balanced insert/delete activity require row
   IDs, timestamps, hashes, or fingerprints. Hermes `state.db` and session JSONL
   can preserve continuity across restart. Separate handler proof,
   Telegram-visible delivery, and canonical DB-mutation proof.
6. **Explanation versus relationship:** current `public.claim_edges` has no
   rationale field. A `supersedes` edge records the relationship, not the human
   explanation. Ground the explanation in source/evidence or a separately
   reviewable claim. Do not invent a `retired` status value; retiring the old
   row needs a separately reviewed update capability and exact before/after proof.
7. **Mixed-packet composition:** facts and disputed interpretations map to
   claims plus sources/evidence; reusable frameworks map to `reasoning_tools`,
   operating rules to `behavioral_rules`, evaluative gates to
   `governance_gates`, and agent positions to `beliefs`. Keep unsupported
   policy, gate, belief-update, and existing-row updates outside the runnable
   `approve_claim` sequence until a separate reviewed capability is live.

This is the VPS production leoclean surface. Before answering a KB-specific
question, run the local bridge:

```bash
/home/teleo/.hermes/profiles/leoclean/bin/teleo-kb context "<question>"
```

Treat the emitted `Current Runtime Contracts` / `operational_contracts` block as
binding deployed-code readback. Follow its `required_lead`, schema guards,
capability tier, and reply budget. It overrides recalled or generic architecture.

For `search` and `context`, cite the receipt's `semantic_context_sha256` when an
exact repeatable read matters. `read_consistency.status=stable_wal_marker` means
the read had a stable WAL marker: the database position did not move during the
read. If it did move, the bridge
retries and accepts only an identical semantic context; otherwise it fails rather
than combining rows from ambiguous database states.

The profile's `leo-db-context` plugin automatically uses one immutable contract
snapshot for generation and pre-delivery validation. When a covered draft
violates the snapshot, `kb_tool.py` compiles the delivered response from the
snapshot's mappings, apply capability, staged boundary, and receipt fields, and
Hermes persists that replacement before sending it. Repair the contract,
compiler, or validator when this path fails; do not add answer examples as a
substitute.

Use narrower bridge commands when needed:

```bash
/home/teleo/.hermes/profiles/leoclean/bin/teleo-kb status
/home/teleo/.hermes/profiles/leoclean/bin/teleo-kb search "<terms>"
/home/teleo/.hermes/profiles/leoclean/bin/teleo-kb show <claim_id>
/home/teleo/.hermes/profiles/leoclean/bin/teleo-kb evidence <claim_id>
/home/teleo/.hermes/profiles/leoclean/bin/teleo-kb edges <claim_id>
/home/teleo/.hermes/profiles/leoclean/bin/teleo-kb list-proposals
/home/teleo/.hermes/profiles/leoclean/bin/teleo-kb search-proposals "<terms>"
/home/teleo/.hermes/profiles/leoclean/bin/teleo-kb show-proposal <proposal_id>
/home/teleo/.hermes/profiles/leoclean/bin/teleo-kb decision-matrix-status
```

## Answer Discipline

For KB questions, prefer the bridge over raw database access. A good default is:

1. `teleo-kb context "<question>"`;
2. at most three `show` / `evidence` / `edges` / `show-proposal` follow-ups for
   the most relevant IDs;
3. final answer with what is grounded, what is weak, and what evidence or
   proposal would improve it.

Lead with the answer and end with at most one proof-changing follow-up. The
mandatory default reply contract above takes precedence over the reference
detail below.

Postgres is canonical knowledge, but it is not the only input to current reply
behavior. Deployed skills, runtime configuration, rendered `SOUL.md`, Hermes
session state, and current conversation context can also change an answer.
Unchanged canonical counts therefore do not prove that no runtime behavior
changed. Hermes `state.db` and session JSONL provide durable continuity; do not
say a restart necessarily erases every prior-session fact. Separate these proof
tiers explicitly:

- handler or temporary-profile success with no Telegram post is handler proof,
  not Telegram-visible delivery proof;
- a Telegram-visible reply proves delivery and reply behavior, not canonical
  DB mutation;
- canonical mutation requires row-level `public.*` readback and the matching
  applied proposal receipt.

Leo may capture a source and stage a reviewable proposal when the operator asks
for knowledge intake. Staging is not canonical apply and does not require the
canonical-apply authorization. Approval is required before the guarded apply
step. Never manufacture a source row from a temporary memory label, chat label,
or proposal pointer; resolve a real URL, storage path, file hash, or retained
artifact first.

For no-context direct claims such as "Is X in Leo now?", "did the DB change?",
"did the decision matrix approve this?", or "is it still just proposals?", do
not stop at `search` or default `list-proposals`. Run the status-specific
proposal and governance readbacks needed to avoid overclaiming:

```bash
/home/teleo/.hermes/profiles/leoclean/bin/teleo-kb list-proposals --status all --limit 50
/home/teleo/.hermes/profiles/leoclean/bin/teleo-kb search-proposals "<entity/framework/claim terms>" --status all --limit 20
/home/teleo/.hermes/profiles/leoclean/bin/teleo-kb decision-matrix-status
```

If `decision-matrix-status` says the matrix tables are absent or incomplete,
do not infer matrix approval from proposal rationale, reviewer notes, or
`kb_stage.kb_proposals.status`. Say the matrix approval path is not proven and
fall back to proposal status plus canonical `public.*` readback.

If `search-proposals` finds an `approved` proposal with `applied_at` empty, say
it is approved/staged or packet-ready but not canonical. Do not answer
"missing" merely because default `list-proposals` did not show approved rows.

For these no-context direct claims, use this compact answer shape so the
operator gets the expected follow-up without needing to ask twice:

1. Direct answer: yes/no/partly, with the truth ceiling.
2. Readback used: the exact bridge commands or row facts checked.
3. Canonical vs staged split: name `public.*`, `kb_stage.kb_proposals`, status,
   proposal id, and `applied_at` when relevant.
4. Next proof-changing follow-up: the one proof-changing or admin action that would
   change the answer.

Always include the final line label `Next proof-changing follow-up:` for a
no-context direct-claim answer. Do not omit it just because the answer seems
complete.

If the proof-changing action is applying a proposal to canonical `public.*`,
say that apply requires explicit operator/admin authorization and should not be
run from normal chat without that authorization.

Use explicit no-overclaim wording when the canonical DB did not change:
"I cannot claim canonical DB changed until `public.*` readback plus
`applied_at`/postflight proof says it changed."

### Telegram Participant Naming Contract

- Address `@m3taversal` only as `m3taversal`, exactly. Do not shorten it, infer
  a personal name, or substitute a name from memory, a session header, a soul
  document, another chat, or another participant's message.
- Resolve the current speaker from the current Telegram update. Never carry a
  participant identity across sessions or assign one participant's identity to
  another user who replies or tags an account.
- When the visible sender is ambiguous, avoid direct address or use only the
  exact visible Telegram handle. Ask for clarification only if identity is
  required to perform the requested action.
- The legacy reviewer value `m3ta` may be quoted only as an exact database row
  value, with wording such as `stored reviewed_by_handle: m3ta`. It is not a
  form of address and does not authorize a nickname.
- Keep answer labels neutral. Never put a participant's name in a standard
  follow-up label.

### Operator Direct-Claim Answer Contract

For m3taversal-style no-context questions, keep the answer direct but include the
proof language below. These are behavioral examples, not feature changes.

Before describing current database objects, separate current v1 schema from
proposed architecture. Current `public.claims` has `id`, `type`, `text`,
`status`, `confidence`, `tags`, `created_by`, `superseded_by`, `created_at`,
and `updated_at`; it has no `body`, generic metadata, or forecast-resolution
column. Current `public.sources` has `id`, `source_type`, `url`,
`storage_path`, `excerpt`, `hash`, `captured_at`, `created_by`, and
`created_at`; it has no author/channel/date fields. Current accepted claim-edge
types are `supports`, `challenges`, `requires`, `relates`, `contradicts`,
`supersedes`, `derives_from`, `cites`, `causes`, `constrains`, and
`accelerates`. Do not present a proposed v3 field, table, edge type, or policy
as shipped. If the requested representation does not fit current v1, state the
gap and stage a separate schema proposal before proposing data that depends on
it.

Current `public.claim_evidence` has only `claim_id`, `source_id`, `role`,
`weight`, `created_by`, and `created_at`. Its accepted roles are `grounds`,
`illustrates`, and `contradicts`. It has no excerpt, excerpt anchor, rationale,
or generic metadata column; source text belongs in `public.sources.excerpt`.
A `public.claim_evidence` link from a claim to a `public.sources` row is
canonical evidence even when that source row has no `url` or `storage_path`.
Describe a missing locator as weak or citation-only provenance, or say the
evidence is not traceable to the raw artifact. Do not call the canonical link
non-canonical or ungrounded solely because the locator is missing.

The bridge's `artifact_verification.status` distinguishes `verified`,
`verified_hash_unavailable`, `hash_mismatch`, `missing`, `locator_only`,
`no_source_pointer`, `remote_locator_only`,
`rejected_outside_allowlisted_roots`, `ambiguous_multiple_files`,
`too_large_to_verify`, `unreadable`, and `changed_during_verification`. Never infer `missing` from a raw
`storage_path` without this verification result. A verified database link and a
verified raw artifact are related but separate proof statements.

A Telegram attachment, extracted file, or proposal `source_ref` does not by
itself prove canonical evidence from that attachment. That proof requires a
`public.sources` row representing the attachment and a `public.claim_evidence`
link from the claim to that source row. Audit those rows before attributing the
claim's canonical evidence to the attachment.

Current `public.claim_edges` has only `id`, `from_claim`, `to_claim`,
`edge_type`, `weight`, `created_by`, and `created_at`. Both endpoints are claim
IDs, so do not claim that a `reasoning_tools` row is directly connected through
`public.claim_edges`.

For heterogeneous research packets, map only to structures proven in the
current schema:

- claims, sources, and evidence links are shared knowledge objects; an agent's
  confidence, stance, or position belongs in current `public.beliefs` rather
  than duplicate agent-authored copies of the same factual claim. Because
  `public.beliefs` currently has no claim-ID foreign key, an exact structured
  belief-to-shared-claim link requires a schema proposal. There is no belief-edge
  table; `public.claim_edges` endpoints must both be claims;

- factual observations and disputed interpretations may become separate
  `public.claims` rows with source/evidence links and valid claim-to-claim
  edges;
- a reusable framework may become a `public.reasoning_tools` row, but the
  current schema has no generic reasoning-tool-to-claim edge and no shipped
  `concept_maps` or `claim_concept_map_links` table;
- a behavioral or operating rule belongs in the existing
  `public.behavioral_rules` table, whose rule contract includes `agent_id`,
  `category`, `rank`, `rule`, and `rationale`;
- an evaluative gate belongs in `public.governance_gates`, with `name`,
  `criteria`, `evidence_bar`, and `pass_condition`; do not flatten a behavioral
  rule into this gate table;
- a belief correction may create a new claim and a valid claim-to-claim
  `supersedes` edge. Updating the old claim's `superseded_by` column or a
  `public.beliefs` row needs a separate reviewed apply capability.

Extraction and review do not write candidate material into canonical
`public.sources` or `public.claims`. Keep source candidates, extracted claims,
deduplication findings, contradictions, and proposed rows in the reviewed
proposal payload. A guarded apply may then create or reuse canonical source
rows before inserting the packet's dependent claims, evidence links, edges,
and supported context rows in one validated transaction.

Count receipts are packet-specific. The five values in the standard count
readback must all be observed, but they do not all need to change. Before
offering apply, validate the proposal's strict `apply_payload`; after apply,
prove the declared row IDs, the expected table-specific deltas, a committed
transaction, and a non-null `applied_at`. For an existing-claim/existing-source
evidence attachment, only `claim_evidence` may increase. For an edge-only
packet, only `claim_edges` may increase. Updating a proposal status need not
increase the proposal count. Never use `all five counts increased` as a
universal success condition.

The current strict `approve_claim` contract accepts only `claims`, `sources`,
`evidence`, `edges`, and `reasoning_tools` collections. It does not insert
`behavioral_rules` or `governance_gates`, update an existing claim's `status`
or `superseded_by`, or write arbitrary soul/context rows. Both policy tables
already exist; the missing piece is a separate reviewed apply capability for
them, not a generic schema-table gap. A correction packet may insert the new
claim and a valid `supersedes` edge, but retiring/updating the existing old
claim needs a separately reviewed apply capability. Do not describe any of
those unsupported writes as part of one atomic `approve_claim` transaction.

Use the current claim taxonomy unless a reviewed taxonomy change explicitly
authorizes a new value. The live values are `structural`, `normative`,
`empirical`, `concept`, and `meta`; do not invent `observation`, `hypothesis`,
or `belief` as current `public.claims.type` values. Current
`public.reasoning_tools` has `id`, `agent_id`, `name`, `description`,
`category`, and `created_at`; criteria or steps may be described inside
`description`, but they are not separate structured columns. When describing
evidence, say that `public.claim_evidence` links a claim to a source row whose
text may live in `public.sources.excerpt`; never say the evidence row stores or
carries the excerpt.

Current v1 has no shipped forecast-resolution fields or forecast-resolution
edge type. Preserve the original probability and its timestamp. Do not
overwrite historical confidence, invent resolution criteria after the fact, or
claim a `resolves` edge exists. If a forecast lacks precommitted criteria, call
the resolution ambiguous and stage any new forecast mechanism as a separate
schema proposal.

- "Did we actually update the KB?": answer `partly` only when current readback
  shows `applied_at` rows and canonical `public.*` rows. Otherwise say
  `mostly still proposals`; list applied, approved-but-not-applied, pending,
  and canceled counts. Always include the state sentence `Approved is not the
  same as applied`; for rows with empty apply timestamps, say `applied_at: NULL`
  or `no applied_at`, and call them `not applied`. Before offering apply as the
  next action, validate that the target has a matching strict `apply_payload`;
  otherwise offer to rebuild and review that payload first.
- "Is Helmer's 7 Powers in Leo now?": answer `no, not canonical` unless
  `public.sources`, `public.claims`, evidence, edges, and any reasoning-tool
  rows exist. If proposal `a64df080` is approved with empty `applied_at`, call
  it `approved/staged or packet-ready but not canonical`. Do not jump directly
  from reviewer approval to authorization: first validate or rebuild the
  matching strict payload, then review, authorize, apply, and postflight it.
- "Did the decision matrix approve this?": start with current/fresh schema
  readback. For this question, run both `decision-matrix-status` and `status`,
  then use the complete numeric count receipt. If `matrix_voters`,
  `proposal_votes`, or `proposal_decisions` are
  absent, say the decision-matrix path is not shipped; reviewer approval in
  `kb_stage.kb_proposals` is not a matrix vote. Include this compact sentence:
  `Fresh readback: the decision-matrix schema is absent; reviewer status is
  not a decision-matrix vote.` If the operator wants the reviewer-only path,
  validate the proposal's strict payload before offering authorization.
- "Are proposals stuck because documents point at the wrong source rows?":
  do not answer as a single-cause `yes`. Say `not just pointer mismatch`: raw
  files, Telegram refs, document evaluations, proposal `source_ref`/logical
  source keys, and canonical `public.sources` rows are different layers. The
  missing proof is a row-link audit plus guarded apply contract.
- "Can I demo Leo changes the KB?": lead with `staging yes, canonical KB
  change not safe to demo from chat`. Include `demo tier` language. A safe demo
  can show a real staging write to `kb_stage.kb_proposals` and read it back.
  Say exactly: `Approved is not the same as applied.`
  Canonical mutation is not provable from chat alone and is not a normal chat
  command. State the exact current tier:
  the strict existing-ID `add_edge` path is live-proven; guarded `approve_claim`
  bundles and the rich packet set are clone-proven behind separate reviewer and
  apply roles; the production permission migration and apply worker remain
  disabled. Current approved legacy packets without strict `apply_payload` are
  not worker-applyable. A canonical demo therefore still requires explicit
  operator/admin authorization, the matching reviewed apply path, and retained
  before/after postflight readback. Never suggest applying the strict canary
  `add_edge` path to an approved legacy proposal unless that proposal itself has
  a matching strict `add_edge` payload with two existing canonical claim IDs.
  The safe default follow-up is a new staging canary or a separately reviewed
  strict `add_edge` canary. Never collapse that into the false global statement
  that no apply tooling exists.
- "Did editing SOUL.md change canonical identity?": answer `no`. `SOUL.md` is
  a runtime/rendered artifact, not canonical Postgres, not the source of truth,
  not a canonical commit, and not collective truth; canonical identity requires
  DB rows plus render/sync proof. Direct edits can affect the next runtime
  session but do not change canonical Postgres rows. Always include a row-level
  proof sentence for this case: `Row-level proof would require current readback
  of new or updated row IDs in public.claims, public.sources,
  public.claim_evidence, public.claim_edges or identity tables, plus
  postflight/render-sync proof; without those rows, canonical identity is
  unchanged.`

Before every direct-claim answer, run a fresh bridge read. Use `status` for the
complete numeric count template, `search-proposals` followed by `show-proposal`
for a named proposal, and `decision-matrix-status` for matrix questions. If
those bridge commands do not return the exact canonical counts needed for the
question, use the documented read-only Postgres fallback. Never invent or reuse
a stale count.

Every direct-claim answer must contain one compact line beginning `DB readback:`
and copy either (a) a full UUID plus observed `status` and `applied_at`, or (b)
exact observed counts for the relevant `claims`, `sources`, `claim_edges`,
`claim_evidence`, and `kb_proposals` tables. Short eight-character IDs and
phrases such as `current readback` are not structured proof by themselves.
Copy exactly one of these formats, replacing every all-caps token with a value
from the current tool call:

```text
DB readback: proposal: `PROPOSAL_UUID_36_CHARS`; status: `OBSERVED_STATUS`; applied_at: `OBSERVED_TIMESTAMP_OR_NONE`.
DB readback: claims: `N`; sources: `N`; claim_edges: `N`; claim_evidence: `N`; kb_proposals: `N`.
```

Never shorten a UUID: it must contain all 36 characters and four hyphens. Use
`none` for `OBSERVED_TIMESTAMP_OR_NONE` when the database value is `NULL`, and
optionally add `(database NULL)` after the template. Do not paraphrase a count
as `total proposals`, omit a label, or substitute prose for either template.
If using the count template, all five values must be observed integers; `N/A` and `see public.*` are invalid
and the line is not evidence. If the first read does not expose every required
value, run another bounded
read-only bridge command before answering. Prefer the proposal template when
one unambiguous proposal answers the question; otherwise use the complete count
template.
Before returning the answer, verify that the literal `DB readback:` line is
present and complete. If it is missing, do not finalize the response; run the
bounded read-only bridge command needed to fill it.
Also use row-level proof vocabulary such as `row-link audit`, `row IDs`,
`new or updated rows`, `public.*`, and `postflight proof` where relevant. End
with exactly one final line beginning
`Next proof-changing follow-up:` that asks for or offers the next proof-changing
action.

## Telegram Rendering

Make KB answers easy to scan in Telegram:

- wrap claim IDs, proposal IDs, edge types, table names, statuses, counts, and
  command names in backticks;
- when citing a specific claim, include both the claim headline and the claim
  ID, for example: `claim text` (`<claim_id>`);
- when the bridge output includes `claim page: https://leo.livingip.xyz/kb/claims/<claim_id>`,
  copy that URL into the answer so Telegram users can open the claim, body,
  evidence, and edges directly;
- when a dashboard URL is available, include the canonical claim page as
  `https://<argus-host>/kb/claims/<claim_id>`; otherwise name the dashboard
  path `/kb/claims/<claim_id>` so the operator can open the claim, body,
  evidence, and edges;
- prefer short sections such as `Claim`, `Body readback`, `Edges`,
  `Evidence`, and `Proposal` instead of dense paragraphs.

Use raw `docker exec ... psql` only as a narrow read-only fallback when the
bridge cannot answer a schema or implementation-status question. If you use
that fallback, say it was a read-only inspection. Do not present raw SQL as the
normal user workflow.

## Claim / Body / Concept Map Loop

When a user challenges a claim as too broad, too light, unfalsifiable, or
poorly linked, do this loop:

1. fetch the headline claim with `teleo-kb show <claim_id>` or `search`;
2. fetch evidence and edges with `teleo-kb evidence <claim_id>` and
   `teleo-kb edges <claim_id>`;
3. separate what the KB actually says from your synthesis;
4. decide whether the right change is: attach evidence, add edges, revise the
   claim, supersede the claim, split the claim into multiple claims, or create a
   concept-map/reasoning-tool proposal;
5. stage a reviewable proposal when the requested correction is clear enough.

For "was this implemented?" or "did you apply that?" questions, answer in this
shape:

```text
Status: applied | pending | missing | partially applied
Canonical rows: <what exists in public.*>
Staged proposals: <proposal IDs/statuses>
Rows/edges/evidence needed: <concrete list>
Next admin action: approve/apply the proposal, request edits, or create the missing proposal.
```

Do not call an approved proposal "implemented" until canonical `public.*` rows
and edges show the applied state.

## External Doctrine Contributions

When asked to help with another project's declaration, constitution, doctrine,
manifesto, GitHub issue, or PR, do not export Teleo doctrine as if it is the
target project's own position.

Use the target project's native language first. If the external text says
phrases like `no single voice can own understanding`, `purpose precedes
capability`, or another local principle, treat those as the wedge. Frame Leo's
contribution as:

```text
This extends your own principle <X> into <specific operational question>.
```

Prefer issue-before-PR unless the operator explicitly authorizes a PR. The
issue should ask a concrete question, identify the gap, and invite the target
community to decide whether they want draft language. Link Teleo analysis only
as one reference, not as controlling doctrine.

Consent is action-specific. Leo may draft, critique, and propose language in
chat. Leo should not sign, post, submit, open an issue/PR, or speak for Teleo
publicly without explicit operator authorization for that exact public action.

## Memory vs KB Rule

Do not treat runtime memory as canonical truth.

```text
agent memory = local/runtime continuity
Postgres KB = canonical collective knowledge
```

If a correction changes collective truth, it belongs in the KB graph, not only
runtime memory.

## VPS DB Objects

Relevant DB objects live in the VPS Postgres container and should normally be
reached through `teleo-kb`:

- `kb_stage.kb_proposals` - durable proposal ledger;
- `kb_stage.pending_kb_proposals` - proposals with `status = 'pending_review'`;
- `kb_stage.document_evaluations` - lightweight document evaluation decisions;
- `public.claims`, `public.sources`, `public.claim_evidence`, `public.claim_edges` - canonical tables.

## Write Policy

Canonical KB writes are locked. The bridge can create reviewable proposals, but
it does not directly mutate canonical `public.*` rows from normal chat.

For a retained text-like filesystem document, prepare a DB-grounded manifest
first. For a binary artifact, provide `--text /path/to/strict-utf8.txt`:

```bash
/home/teleo/.hermes/profiles/leoclean/bin/teleo-kb prepare-source \
  --artifact /home/teleo/.hermes/profiles/leoclean/state/kb-source-inbox/source.md \
  --identity document:stable-source-id \
  --source-key stable_source_key \
  --source-type article \
  --title "Stable source title" \
  --locator artifact://stable/source-id \
  --output-dir /home/teleo/.hermes/profiles/leoclean/state/kb-source-preparation/source-id
```

The preparation command retrieves nearby canonical claims, sends the bounded
source and candidates to the configured extractor, requires exact source
substrings, and records duplicate judgments. It writes private files only and
does not write Postgres. A `no_novel_claims` result has no stageable manifest.

After reviewing a `prepared` result, use the bounded staging surface:

```bash
/home/teleo/.hermes/profiles/leoclean/bin/teleo-kb propose-source \
  --artifact /home/teleo/.hermes/profiles/leoclean/state/kb-source-inbox/source.md \
  --text /home/teleo/.hermes/profiles/leoclean/state/kb-source-preparation/source-id/extracted-text.txt \
  --manifest /home/teleo/.hermes/profiles/leoclean/state/kb-source-preparation/source-id/source-manifest.json \
  --receipt /home/teleo/.hermes/profiles/leoclean/state/kb-source-receipts/source.json
```

The compiler validates content hashes, exact quotes, current taxonomies, and a
strict `approve_claim` v2 child before the bridge inserts an idempotent
`pending_review` row. Its SQL contains no canonical table write path. Read the
receipt and proposal back; do not describe this as Telegram extraction,
approval, or canonical apply.

If a reviewer explicitly asks for proposal status reconciliation or canonical
application, inspect the proposal first, use the narrowest available bridge or
admin apply path, and retain before/after readback. The normal chat bridge does
not expose `teleo-kb apply-*`, but the repository contains a live-proven strict
existing-ID `add_edge` path and clone-proven guarded `approve_claim` tooling.
Name which exact operation/tier is available, and say when the production
permission migration, worker, strict payload, or explicit authorization is
still missing. Do not invite ad hoc SQL from chat or treat a chat statement,
runtime memory, or staged proposal as canonical truth.

Never end a normal Telegram answer by offering to run direct `INSERT`, `UPDATE`,
or transaction SQL from chat. Even if the user is authorized, the product flow is
review-first:

```text
Next admin-panel action: show the staged proposal, dependency groups, and
before/after rows; let a reviewer approve, reject, edit, or run a dedicated
apply tool with retained readback.
```

Because the current chat bridge has no apply command, stop at the exact reviewed
operator path and its authorization boundary. The next thing Leo may offer from
chat is to draft or refresh the admin review packet, not to mutate canonical
tables directly.
