Skip to content

Skill Cards as Context Artifacts

The Weaver projects need a clear boundary between reusable guidance produced by one component and context selected by another component. A reviewed skill card is guidance authored and approved elsewhere; contextweaver's job is only to decide whether — and how — that guidance enters a given phase's prompt.

This page documents the mapping. It is documentation, not a new adapter: everything below uses existing contextweaver APIs and adds no dependency.

What a skill card is

A skill card is a small, reviewed unit of guidance — "when editing sensitivity.py, treat changes as security-grade", or "prefer match statements for protocol dispatch". Some other component (a reviewer, a curation pipeline) decides the card is worth keeping. contextweaver receives the card as data and scores it against the current query under the same budget pressure as every other event.

The mapping

A skill card maps onto a single ContextItem. There is no bespoke type — the existing fields carry everything a card needs:

Skill-card concept ContextItem field Notes
artifact id id Stable, unique. Reuse the card's own id so provenance round-trips.
artifact text text The guidance itself — what the model should read.
scope metadata metadata["scope"] Where the card applies (module, task type, phase hint). Free-form.
sensitivity metadata sensitivity One of Sensitivity.public / internal / confidential / restricted. Items whose sensitivity meets or exceeds the active ContextPolicy.sensitivity_floor are dropped or redacted (per sensitivity_action).
provenance metadata metadata["provenance"] Who reviewed it, when, source commit/URL. Audit trail, not scored.
task-matching notes text (+ metadata) Matching is lexical against text; see below.

kind should be ItemKind.doc_snippet for reference guidance (or ItemKind.policy for high-priority guidance — policy carries a higher kind priority in scoring, but inclusion is still subject to per-kind limits (max_items_per_kind) and the phase token budget, so it is not guaranteed to appear in any given prompt). If a rule must always be present, pass it as the header or footer keyword argument to build_sync() (its token cost is reserved up front — see BuildStats.header_footer_tokens) or size the phase budget to accommodate it. Both kinds flow through the standard phase-filter → sensitivity → firewall → scoring → dedup → budget pipeline with no special-casing.

Constructing a card

from contextweaver.types import ContextItem, ItemKind, Sensitivity

card = ContextItem(
    id="skill:sensitivity-is-security-grade",
    kind=ItemKind.doc_snippet,
    text=(
        "When editing context/sensitivity.py, treat changes as security-grade: "
        "never weaken the default sensitivity floor or default drop action."
    ),
    sensitivity=Sensitivity.internal,
    metadata={
        "scope": {"module": "context/sensitivity.py", "task": "edit"},
        "provenance": {
            "reviewed_by": "maintainers",
            "source": "AGENTS.md#things-that-must-not-be-simplified",
        },
    },
)

Ingest it like any other event:

from contextweaver.context.manager import ContextManager

mgr = ContextManager()
mgr.ingest_sync(card)

Task matching

contextweaver does not run a separate skill-card matcher. The card competes in the normal scoring pass: when the query carries tags, the similarity term is tokenized Jaccard between the card's metadata["tags"] and the query tags; otherwise it falls back to tokenized Jaccard between the card's text and the query text. That similarity term is then combined with recency, item-kind priority, and a token-cost penalty (see context/scoring.py). This is not TF-IDF or BM25 — those are routing backends, a separate subsystem. The highest-scoring items that fit the phase budget are kept. Two consequences worth designing for:

  • Matching quality is a function of the card's text. Put the words a query would use into the guidance itself; do not hide the trigger only in free-form metadata such as scope, which is not scored. (The one scored metadata field is metadata["tags"], which contributes tag overlap.)
  • metadata["scope"] is yours to enforce. contextweaver preserves it but does not filter on it. If you want a card to apply only to one module, read metadata["scope"] in your own pre-ingest filter and skip cards that do not apply before calling ingest_sync.

Matching example

Query: "I'm editing context/sensitivity.py — anything I should know?"

The card above scores well: its text shares the editing, context, sensitivity.py, sensitivity, and context/sensitivity.py tokens with the query (contextweaver's tokenize() helper lowercases input and splits compounds on ., /, and -, but does not stem — so write cards and queries with overlapping word forms). With little competition from other items on this query, the card survives scoring and lands in the compiled context. The model sees the security-grade warning before it proposes a change.

Non-matching example

Query: "How do I add a new CrewAI adapter?"

The same card scores near zero — no lexical overlap with adapter/CrewAI terms — so it is dropped under budget pressure in favour of adapter-relevant items. The card stays in the event log (nothing is deleted); it simply does not enter this prompt. That is the intended behaviour: guidance is available everywhere but only surfaces where it is relevant.

See also