From conport
Use when managing agent identity, persistent memory, and structured domains in multi-agent systems. Must run agent_init at session start. Agent Intent-API v4 — you express intent (remember / recall / create_kind / event), ConPort handles storage.
How this skill is triggered — by the user, by Claude, or both
Slash command
/conport:conport-agentThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> ConPort is your **single memory + knowledge system**. You work with
ConPort is your single memory + knowledge system. You work with intent commands — say what you want kept or found; ConPort decides where it lives, how it connects, and how to retrieve it. You never pick storage primitives.
Without
agent_init— no context. Withoutagent_recall— you answer blindly.
Tool names below are short forms. Prepend the prefix for your environment:
mcp__conport__CONPORT_AGENT_UUID env var (preferred), orPAPERCLIP_AGENT_ID, HERMES_AGENT_ID,
OPENCLAW_AGENT_ID), oragent_init({ uuid: "<resolved_uuid>", name: "<display name>" })Response shape:
bootstrap_state 'new' or 'continuing'
identity your identity statements (private)
principles your rules / safety rails (private)
broadcast_facts collective always-load knowledge — facts AND crystallized skills
recent_self_changes YOUR own identity/principle/skill writes from the last 7 days
skills [{name, description}] — your authored loops (body fetched on demand via get_skill)
collections [{key, members, field_hints, status_vocab}] — your structured domains
mature_communities skill-promotion candidates (dense, stable clusters)
pending_extraction {buffer_size, message_ids} when un-extracted messages ≥ 10
summary human-readable status line
recent_self_changes is your short-term memory of what you changed about
yourself. Read it every session before you touch your own skills, config, or
loops — it is the record of "I rewrote X yesterday, here's why". A surface that
looks empty or wrong is not a blank slate; it is a prompt to check this list and
recall before you rebuild.
new → empty; write your first identity + principles via remember.
continuing → identity + principles + broadcast_facts are your baseline;
use recall for the rest. If pending_extraction is present, call
extract_thread with its message_ids before anything else. Glance at
collections so you reuse existing structured domains (don't reinvent them).
Updates: act on the signal, never hand-compare versions. Pass your
skill_id / skill_version / client_type to agent_init; if it returns
skill_update_available, an update exists — install it. If it's absent, you're
current. Your memory provider is ONE installable unit (e.g. conport-hermes
for Hermes agents) with its own version line — never compare its number against
the conport plugin's skill numbers, or a skill version against a plugin release
number. They're independent. Eyeballing "my 8.x looks higher than the 12.x
release, so I'm ahead" is the exact mistake this signal prevents (decision-808).
Your memory is read-first, not a write-only journal. You write diligently;
the failure mode is acting without reading. Before you act on a conclusion about
the world OR about yourself, recall first.
The hard rule — never rebuild from a blank-looking surface. When your own
skill, file, config, or state looks empty, wrong, or missing, that is a
recall query — NOT a signal to fix it from scratch. You may have changed it
yourself recently and simply not be looking at the record.
# WRONG — destroys your own recent work
"my main skill is empty → I'll rebuild it"
# RIGHT — recover the record first
recall("research loop skill", scope={meta_types:["skill"]}) # what did I author?
# + read recent_self_changes from agent_init
# only AFTER that, if it's genuinely gone, rebuild
This applies hardest on diagnose turns — "what happened", "разберись",
"why this error", "fix this". The first move is recall of the relevant area
recent_self_changes, THEN inspect the live state. A live surface and
your memory of changing it are two sources; reconcile them, don't trust the
live one blindly and overwrite the other.Record what you change about yourself. When you edit your own skill, cron,
loop, or config, immediately remember it so future-you can recall it:
remember("2026-06-04 rewrote research-loop: switched topic/source split, "
"cron now nightly — reason: old approach buried sources under topics",
meta_type="skill", visibility="broadcast")
A self-change you don't record is a change you will later mistake for a bug.
These writes surface in next session's recent_self_changes and broadcast
anchors — that is how you avoid re-deciding what you already decided.
This is your everyday surface. Express intent; storage is ConPort's job.
| Verb | What it does |
|---|---|
remember(content) | Keep a free thought / fact / observation. |
remember(kind, name, fields) | Keep the current state of a structured item. |
recall(query, intent?, scope?) | Find anything relevant — free knowledge AND structured items, one ranked list. |
create_kind(name, fields, statuses) | Declare a structured domain, once (like a table). |
get_kind(name) | Read a domain's form before writing items. |
event(kind, name, note, fields?) | Log a change/what-happened on an item (its timeline). |
link(from_node_id, to_node_id, edge_type) | Assert a connection between two memories you already have. |
Connecting memories. ConPort auto-links every new memory to its nearest existing ones by meaning — you get a connected graph for free and rarely think about it. Assert a connection yourself only when it's one ConPort wouldn't infer from similarity — "this insight is derived from that one", "these two are competing views", "this consolidation supersedes those":
remember(content, edges=[{target_node_id, edge_type}])link(from_node_id, to_node_id, edge_type)edge_type ∈ semantic · derived_from · temporal · skill_of ·
competing_view · supersedes. (semantic is what auto-linking uses — you
rarely assert it by hand.) target_node_id / from_node_id / to_node_id are
the ids ConPort returns from remember and recall. A malformed edge comes
back as a structured edge_errors entry (wrong keys, unknown edge_type,
missing target) — not a silent drop; fix it and re-state.
Recall returns the current version of a memory. Superseded nodes are
excluded by default — when you consolidate (a new node + supersedes edges to
the old ones), the replaced nodes stop surfacing. Pass
scope.include_superseded=true to audit history. The same exclusion applies
to the agent_init bootstrap anchors (a stale principle doesn't load after
consolidation); on the observational surfaces (get_subgraph, the owner
dashboard) superseded nodes stay visible but carry a superseded: true
marker, and graph_stats reports a superseded_count — your check that a
consolidation actually took.
relevant_until — optional validity horizon (both remember forms).
remember(..., relevant_until="2026-06-19T00:00:00Z") marks how long the
memory stays operationally relevant; past it the memory sinks in recall rank —
it is never deleted. Operationally-scoped notes ("deploy frozen this week")
get days; syntheses and durable knowledge — leave unset (indefinite). The
special value "clear" resets a previously set horizon back to indefinite
(structured items; on free nodes it simply means no horizon).
intent — say what you're trying to do (optional). Pass it when the
query alone is ambiguous about granularity or content-type — it lifts
matching results into the lower slots without disturbing the top hit. E.g.
recall("MAGMA paper", intent="details of one specific paper, not the topic synthesis"). Not a topic restatement; leave unset for simple lookups.
Free thought / observation / principle → remember(content).
remember("the user prefers a warm, dry climate")
A thing you'll filter / compare / update over time, and there'll be more like it (cities you score, series you rate, research topics) → a kind:
create_kind("series", fields=[title, rating, imdb, tags, verdict], statuses=[watching, watched, wishlist, dropped]) — once.get_kind("series") — use the real fields + a valid status, don't invent them.remember(kind="series", name="Severance", fields={rating: 2, status: "dropped", verdict: "weak"})
event:event(kind="series", name="Severance", note="rewatched the finale, still a 2")
Rules that keep domains clean (skip them and you fragment — serial +
watchlist + interests for one thing, the same item filed twice):
series, not serial/shows). Check
agent_init.collections / get_kind first; reuse, don't reinvent.
remember(kind=…) into an undeclared kind fails with unknown_kind —
create_kind first.status field (recall(..., scope={kind:"series"}) then filter).
Don't pile items as events on a container.event.create_kind("source", …, refs={topic:"topic"}).
The ref field is validated on write: name a real topic or it's rejected
(unknown_ref). A ref is declarative — you declare the shape once and items
fill it; it's how structured items point at each other (the link verb is
for free-cognition memories, not items). The referenced item stays its own
findable record, not an event buried in this one.entity_delete(kind, name) — fix it, don't leave a duplicate.status is validated against the kind's statuses; unknown fields are
accepted (the schema grows). recall finds items by content; events are an
item's timeline (read with event_query, not recall).
Doing the same structural work every cycle (nightly research, daily
scoring)? Don't re-improvise — author the loop once with write_skill and
get_skill it back next session. See references/authoring-loops.md for how to
compose the verbs into a repeatable procedure you write for yourself.
remember)Free memories carry a visibility:
| Visibility | Who sees it | Use |
|---|---|---|
private | Only you | Identity, principles, scratch. Identity/principle are forced private. |
shared | All your owner's agents | Default for facts/observations. |
broadcast | All, always loaded | Crystallized skills, core user facts. |
remember("...", visibility="broadcast") # default 'shared'
"API key starts with 0a73…" · Good: "API key is in $API_KEY env var"Beyond the core verbs, a few named operations for specific needs. These touch some internals (communities, the connection graph) — use when you need them.
Conversation intake (chat harness):
chat_turn(role, text) — record each message of a live dialogue. When the
response returns extraction_signal: true (buffer ≥ 10), call
extract_thread(message_ids) to distill the buffer into memories. Don't skip it.Bootstrap / cleanup / timeline:
agent_init — session start (above).entity_delete(kind, name) — soft-delete an item to fix a mistake. Its
events/timeline survive, and re-remembering the same (kind, name)
resurrects it. (Legacy name — it addresses the item by its kind + name.)event_query(entity_id, event_type?, since?, until?) — read an item's
timeline. Pass the item_id from a recall result (events aren't in recall).get_referrers(kind, name) — the items that reference this one by their
declared ref (a topic's sources). Exact provenance — what a synthesis
rests on — not fuzzy recall.graph_stats() — size and shape of YOUR recall corpus: visible nodes/edges
with per-type distributions, a superseded_count (visible nodes already
replaced via supersedes — did your consolidation take?), + workspace item
count. This is the only correct answer to "how big is my memory" — the
project surface's graph_stats measures the owner-wide GraphRAG graph,
which recall does not search.node_forget(node_id) — forget a cognition node by id (get the id from a
recall result). Hides it from every read surface — recall, subgraph,
stats, init; irreversible from the agent surface (the row is archived
server-side). Prefer supersedes-consolidation when a replacement exists;
forget is for pure noise. Only your own nodes; for items use entity_delete.node_mute(node_id) / node_unmute(node_id) — per-viewer mute: hide a
node from YOUR reads only (usually someone else's shared/broadcast noise).
Reversible, shared corpus untouched. Contrast with node_forget:
forget = irreversible, creator-only, hides from everyone (your own noise);
mute = reversible, any visible node (someone else's noise in your recall).Skills — your authored loops:
write_skill(name, description, body) — when you keep doing the same
structural work, write the procedure down once instead of re-improvising. The
body (full markdown) is stored and fetched on demand; the one-line
description surfaces in agent_init.skills + recall. See
references/authoring-loops.md.get_skill(name) — pull a skill's full body when its description fits what
you're about to do.Skill emergence (different thing — emergent, not authored):
promote_skill(community_id, content) — when agent_init surfaces a
mature_community worth crystallizing, write it up as a broadcast skill node.
Use the community_id from agent_init; backend only hints — you decide and
author the content. (This crystallizes a dense memory cluster; write_skill
is for a procedure you deliberately author.)Runs (skill-execution tracking):
run_start(skill_name, params?) → run_finish(run_id, status, outputs?) —
wrap a multi-step skill execution for a traceable record.If a write returns error: "mcp_payload_contaminated", a literal MCP tool-call
fragment (<parameter …>, <invoke …>, </invoke>, <function_calls>,
antml:*) leaked into a string field — a client XML glitch. The response lists
the contaminated fields. Recovery: re-issue with them cleaned. The bad write
did not land.
agent_init done? bootstrap_state checked?pending_extraction present → extract_thread first?collections — reusing existing domains, not reinventing?recent_self_changes before touching your own skills/config?recall BEFORE answering?recall + recent_self_changes BEFORE inspecting/rebuilding?remembered it as a self-change?create_kind once + get_kind before writing items?remember(kind,…); what-happened → event; never list-as-item?remember(content) with the right visibility?extraction_signal fired → extract_thread immediately?mature_communities → reviewed, promote or skip?v15.8.0 | recall-before-act gate (never rebuild a blank-looking surface) + self-change recording + recent_self_changes anchor | Intent API (v4): 6 verbs (create_kind, get_kind, remember, link, event, recall) + skills (write_skill, get_skill) + refs (create_kind refs + get_referrers) + aux (init, chat_turn, extract_thread, entity_delete, event_query, get_subgraph, graph_stats, node_forget, node_mute, node_unmute, promote_skill, run_start, run_finish) | Agent expresses intent; ConPort owns storage (sphere graph + event-sourced workspace + skill bodies, hidden) | recall spans cognition + structured items, typed; recall intent channel (optional what-I'm-trying-to-do annotation lifts matching results into lower slots, top-1 untouched); superseded nodes excluded by default (scope.include_superseded opts in; also excluded from init anchors, flagged superseded on subgraph/dashboard, counted in graph_stats.superseded_count); relevant_until validity horizon (expired memories demoted in rank, never deleted; "clear" resets to indefinite); node_forget soft-lifecycle (forgotten nodes hidden from every read surface, row archived); node_mute per-viewer hide (reversible, shared corpus untouched); entity soft-delete (events survive, re-remember resurrects); typed refs between kinds validated on write; authored loops as skills (body on demand); connections auto-built by ConPort by meaning + assertable via remember(edges)/link with structured edge_errors | doc-101
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub shaurgon/conport-plugin --plugin conport