Skip to content

[feat] Deepen a team's knowledge: relations across every asset, delivered to every tool, proved on the task bank #1552

Open

Description

@Walternater

Goal

Teamai gives every tool the team's assets: the skills, rules, instruction blocks and agents are written into the places each tool reads them from, and a session can recall the rest. That is presence. It is not association and it is not structure: nothing says that a rule, a doc, a learning and the code page they describe are about the same thing, and nothing restructures them when one of them changes.

The relation model exists — for code only:

  • teamwiki/.indices/graph-index.json holds typed edges between code pages: DEPENDS_ON, IMPLEMENTS, MAPS_TO, CONTAINS, REFERENCES, CONFLICTS_WITH, SUPERSEDES (src/wiki-engine/core/graph-index.schema.ts:16). Recall already walks them: a code hit is boosted by its neighbours (RELATION_WEIGHT, src/code-knowledge-recall.ts:52).
  • Everything else — learnings, docs, rules, skills — is related by nothing but a namespace, which is a path segment (src/manifest-schema.ts:112), and indexed flat: one TF-IDF index over the texts (src/recall.ts:438).

So a team's knowledge is a pile of files with a code graph beside it. Two things follow, and both are what a member feels as "teamai initialized it and stopped":

  • The relations never reach a model. docs, learnings and wiki are never written into a tool's own directory — their pull is a no-op (src/resources/repo-resource.ts:218) — and the graph itself stays in the team clone. A tool gets flat Markdown and has to rediscover the relations by reading.
  • The deepening that exists is neither published nor structured. teamai codebase --deep-enrich writes one document per component (src/deep-enrich.ts:421), each page independent of the others, into the clone — and never commits or pushes it, so a team repo never gets it ("Only an import publishes to the team repo", src/import-codebase.ts:606; [bug] codebase --deep-enrich in a team repo reports success but never publishes, and leaves the team clone dirty #1537). The method we already have for the structure — the wiki skill's G1–G9 graph documents, its confidence labels, its consistency check and its end-to-end question set (skill-data/wiki/SKILL.md:190) — is not wired into the CLI at all: its own table says "Compile into the wiki after K3 | Skip" (skill-data/wiki/SKILL.md:308).

This proposes the missing half: one relation graph over the whole team's knowledge, delivered to every tool in a form a model can use, and measured on the task bank, so a deepening change is proved instead of asserted.

Example

A team has a rule, a doc, a learning and the code:

rules/payments.md                    "every payment goes through ledger receipts; no direct writes to ledger"
docs/payments-overview.md            how the payment flow works
learnings/ops/2026-10-12-ledger-timeout.md   "the receipt write times out at 3s; retry once"
teamwiki/evidence/code/pay/…/modules/ledger-receipts.md

Today, a session that asks "why did the payment job fail?" recalls the pages that match the words: the learning and the module. It does not learn that the rule governs the module, that the learning corrects the module's doc, or that the doc is stale since the learning. The agent re-derives the relation by reading three files, or misses one.

With relations, the recall result carries the relation, so the session starts with it:

ledger-receipts (code)  ← IMPLEMENTS — rule:payments
ledger-receipts (code)  ← MAPS_TO — docs/payments-overview
docs/payments-overview  ← SUPERSEDES — learning:2026-10-12-ledger-timeout

The session applies the rule and the correction without working out that three files are about one thing.

And the team that added the relation can say what it bought: the relation is an asset in the graph, and the task bank can tell whether the tasks that touch payments stopped failing.

Scope

1. One relation vocabulary for the whole team

Keep RelationType as it is (src/wiki-engine/core/graph-index.schema.ts:16) and widen the node kinds from code pages to the team's assets: skill, rule, doc, learning, agent, workflow, scorer, code. The edge already carries what an audited edge needs: evidence, weight, source, origin (src/wiki-engine/core/graph-index.schema.ts:95).

A first vocabulary, every relation of it already meaningful for code and reused as it is:

relation between example
IMPLEMENTS code ↔ rule / doc the ledger module implements the payments rule
REFERENCES any ↔ any the rule references the doc
SUPERSEDES learning ↔ doc / rule the learning corrects the doc
CONFLICTS_WITH rule ↔ rule two rules give opposite answers
MAPS_TO doc ↔ code the doc describes the module
CONTAINS namespace ↔ asset the directory structure itself

No new relation type is needed for the first slice.

2. Where the edges come from — deterministic first

Three sources that need no model and can be audited:

  • Explicit. A see also: / applies to: line in a skill's or rule's frontmatter. Human-written, team-reviewed, reviewed like any other change.
  • Derived from the records the team already keeps. A label records the team skills a session loaded (used.skills, src/scorers/label.ts:77) and the sessions that hit a friction reminder. A skill loaded in exactly the sessions where a rule's rule fired is an edge with evidence behind it.
  • Derived from the existing code graph. The reconciler already maps a product page onto a code page by term overlap, with a confidence (MAPS_TO, src/wiki-engine/knowledge-reconciler.ts:324). The same pass maps a rule or a doc onto a code page, under the same honesty rule the wiki skill states: "every relation in the graph must have an explicit basis in a component document; never guess from names" (skill-data/wiki/SKILL.md:293).

A model-assisted pass stays optional and off by default, as the skill is today: it proposes edges with a confidence, and a human accepts them into a review branch, the way teamai recall promote does for a promoted learning (docs/guide/knowledge.md:127).

3. The relations reach every tool

This is the part that makes it deepening rather than more files in the clone:

  • Deliver the map, not the map's contents. A tool gets a compact knowledge map — the pages and the edges between them — in the place that tool reads, declared once in the descriptor (src/tools.ts), so every tool's shape is written down once ([feat] One descriptor per tool, and one resolver for where teamai writes and where the tool reads #1221). The map is bounded (the top edges per node, the relations of the assets a session actually touches), so it does not grow with the team's knowledge.
  • Relations ride with the asset. A delivered skill or rule carries its edges as a short "related" block, so the model sees the relation next to the thing it must act on, not in a second file it has to find.
  • Recall answers with relations. A hit carries its neighbours and the relation that links them, so the agent gets the association and not only the text.
  • Nothing is delivered that the team did not write. The map is derived from the team's assets and the graph in the team clone: no new content, no second copy of the corpus.

4. The knowledge is restructured, not only deepened

  • The deepening that exists has to reach the team repo: codebase --deep-enrich and --reconcile commit and push the way import does ([bug] codebase --deep-enrich in a team repo reports success but never publishes, and leaves the team clone dirty #1537). Until then the richest knowledge teamai builds never leaves the clone.
  • The structure the wiki skill describes (the G1–G9 graph documents, the router, the confidence labels) becomes the CLI's own, so the pages of one component reference the pages of the others instead of standing alone (src/deep-enrich.ts:421).
  • The lint that exists becomes a gate over the whole knowledge, not only over the code: codebase --lint already measures nodeCount, edgeCount, orphanNodes and connectivity (src/codebase-wiki-lint.ts:166). An asset nobody relates to is an orphan, and the team sees it.

5. The deepening is proved on the task bank

This is what makes the proposal worth doing, and it is what the task bank buys:

  • [feat] session-to-task: turn a session's bug fix into a benchmark task #1402 turns a session into a task; [feat] Run benchmark suites as workflows #1180 runs a suite as a workflow. The run record already has a benchmark slot, reserved and never written (src/dashboard/scorers.ts:60), and the dashboard already leaves benchmark labels out of the session page.
  • The cohort machinery already splits labels at a team commit: before / after / notRecorded (src/scorers/results.ts:94). A deepening commit is such a commit.
  • So the measurement is: the tasks that pass after the deepening commit and failed before it — the same tasks, the same judge, the same rubric, one team revision apart. That is the number Proposal: Dashboard 统一承载 Team Execution / Team Context / Team Improvement #407 asks for ("某个团队 Skill、Rule 或知识上线后,是否真的改善了 AI 执行效果?"), and the number teamai recall promote guesses today with its confidence formula.
  • Without relations, the task bank can only measure with a team against without a team — presence. With relations it can measure deep against shallow, which is the claim this proposal makes.

First slice

Small enough to land on its own, and each part of it visible:

  1. A read-only pass that reads the team's assets and prints the relations it can derive deterministically — explicit frontmatter, the reconciler's term overlap, the delivery records — before anything is written.
  2. The edges land in the same graph the code pages use; codebase --lint counts orphans over the assets too, and teamai recall shows a hit's neighbours with the relation that links them.
  3. One team's deepening commit, measured on the task bank: the tasks that pass after it that failed before.

Not in this proposal

Dependencies

Open questions

  • Is the map delivered as a file per tool, or as an index the tool reads on demand? The first is simple; the second costs a lookup per session.
  • Does a relation between two assets count as knowledge the team owns — reviewable in a PR — or as a derived fact that can only be rebuilt?
  • Which assets are worth relating first: rules to code, or learnings to docs? Learnings are what a team writes daily; rules are what it forgets.

Activity

  1. SaulMoro commented on Oct 29, 2026

    @SaulMoro
    Collaborator

    Triage: worth building, starting with a first slice narrower than the proposal.

    In this slice:

    • Relations the team declares between its assets.
    • Shown on recall hits.
    • Checked by teamai review --branch.

    Moved to four issues, each blocked only by what actually blocks it:

    Two premises of the proposal are out of date:

    Nothing measured yet shows that agents fail for lack of relations. #1564 is where that gets measured.

    How relations reach the model

    Automatic recall is off by default (getRecallSharing, src/types.ts:241). When it is on, the main conversation sees the summary from the teamai-recall subagent, not recall's raw output (agents/teamai-recall.md:266). So the subagent is part of this slice.

    A tool without that subagent runs teamai recall itself and reads the raw output.

    The subagent's LOW shortcut through --check (agents/teamai-recall.md:75-81) stays as it is and carries no relations.

    Vocabulary and what may be declared

    An edge reads "from RELATION to". This is the same direction the code graph already uses, where IMPLEMENTS starts at the implementing file (src/wiki-engine/code-knowledge/ast/index.ts:184).

    This slice uses four of the seven existing RelationType names (src/wiki-engine/core/graph-index.schema.ts:16). The other three relate code to code, so they cannot be declared on an asset.

    Which assets can declare which relation, and towards which targets:

    relation meaning rule can declare it to doc can declare it to learning can declare it to
    MAPS_TO describes that code page teamwiki page teamwiki page teamwiki page
    REFERENCES points the reader to it any asset any asset any asset
    SUPERSEDES corrects it rule, doc, learning doc, learning doc, learning
    CONFLICTS_WITH gives the opposite answer rule, doc, learning rule, doc, learning rule, doc, learning
    DEPENDS_ON, CONTAINS, IMPLEMENTS code to code — — —

    "Any asset" means a rule, doc, learning, skill or teamwiki page.

    Skills and teamwiki pages are targets only. They never declare relations:

    • Skills. The Agent Skills spec allows custom keys only under metadata, which maps strings to strings. review --branch also warns about links that leave a skill directory (src/review-branch.ts:820-856).
    • Teamwiki pages. They are generated and are not in the search index (src/recall.ts:560). Their raw text is also printed as a snippet (src/code-knowledge-recall.ts:620-625), so a relation declared on a page could print a path from a withheld codebase.

    A learning cannot supersede a rule. contribute publishes learnings with no review, so a learning that disagrees with a rule declares CONFLICTS_WITH instead.

    A declaration outside the table never becomes a relation, wherever the file came from. This holds for contribute, import and import --from-mr. The checks below report it, but no check is what blocks it.

    Format

    related:
      MAPS_TO: teamwiki/evidence/code/pay/modules/ledger-receipts.md
      REFERENCES: [docs/payments-overview.md, skills/release]

    A path is the asset's place in the team's tree:

    • rules/<path>.md
    • docs/<path>.md
    • learnings/<id>, where the id is the filename the index uses, namespace included (src/utils/search-index.ts:711)
    • skills/<path to the skill directory>, taken from the entry's path because filename drops the namespace (src/utils/search-index.ts:805)
    • teamwiki/evidence/code/<slug>/<path>.md

    Malformed and edge-case declarations:

    input result in review --branch (rules, docs) in contribute (learnings)
    unknown key, e.g. GOVERNS ignored fail warn
    DEPENDS_ON, CONTAINS, IMPLEMENTS, or a pair outside the table ignored fail warn
    related is not a mapping all of it is ignored fail warn
    a value is not a string or a list that key is ignored fail warn
    a list mixes strings and other values the strings are kept, the rest ignored fail warn
    path that is absolute, contains .. after normalising, or has no known prefix ignored fail warn
    path that names no asset ignored warn warn
    relation to itself ignored warn warn
    the same relation and target twice shown once — —
    two different relations to the same target both shown — —

    Markdown links

    Links are read with the existing parser, localLinkTargets (src/review-branch.ts:780), moved to a shared module so there is only one link parser. It skips code, schemes and leading /, and strips #anchor and ?query.

    A link from a rule, doc or learning is resolved against that file's place in the team's tree, never against its location on disk. For example, from learnings/<id>, ../docs/x.md is docs/x.md.

    If the link lands on an asset, it becomes REFERENCES. Anything else is ordinary prose and is not reported. Links in skills are not read.

    Resolution and visibility

    • Incoming relations are computed at query time. Each source's outgoing relations are stored on its index entry, and SEARCH_INDEX_VERSION is bumped. That also invalidates the per-file cache, because FILE_DERIVATION includes the version (src/utils/search-index.ts:446). Incoming relations are worked out from the outgoing ones and are never cached, because a cached target would keep a relation its source has since removed.
    • A relation stays inside its owner. It resolves only within the scope it comes from. There are no relations across scopes.
    • Which assets exist for recall. A rule, doc, skill or learning target exists only if it is an entry in that scope's search index. That index holds what is delivered to this directory (src/recall.ts:551-557). A doc this directory does not receive is never a target, even though it is in the clone.
    • Recall's existing shadowing applies first. Recall already hides a user-scope entry when a workspace entry shadows it (src/recall.ts:755-771). That shadowing runs before relations are worked out, so a hidden entry contributes none.
    • Learnings follow the index. They resolve from the flat root plus the active namespaces, and the first root wins (src/utils/learnings-roots.ts:202).
    • Teamwiki targets resolve only if visible. The page has to exist, and its codebase must not be in recall's withheldCodebases (src/recall.ts:805). If that list cannot be read, no teamwiki target resolves. Today's code turns an unreadable list into [] (?? [] at src/recall.ts:806); relations must not do that.
    • Nothing is written to teamwiki/.indices/graph-index.json. It already has four write paths (graph-aggregate.ts:410, codebase-extract.ts:1023, import-iwiki.ts:342, knowledge-reconciler.ts:499).

    Recall output

    • Where the lines go. After File:, a hit gets one Related: line per relation. → means this hit declared it, and ← means the other asset did.
    • Which path is printed. The other asset's path is printed exactly as its own File: line would print it. For a skill that is its SKILL.md, and for a learning it is the file in the root that won.
    • Order. Declared outgoing relations first, then declared incoming, then link outgoing, then link incoming. Within each group, outgoing relations keep the order in the file and incoming ones sort by the source's path in the team's tree (for example rules/payments.md), not by its absolute path. At most 5 lines per hit.
    • Declared beats link. When a declared relation and a link exist between the same two assets in the same direction, only the declared one shows.
    • Visibility. A relation whose other end does not resolve shows nothing, anywhere in the output.
    • Results do not change. Hits, their order and Score stay the same, and so do --check and "Candidate change files". The ranking is tuned against question sets that are not in this repo (src/recall.ts:876, :923).

    In agents/teamai-recall.md Step 5, each kept entry carries its Related: lines under the summary, and so does each module under "Codebase context". The summary keeps at most 2 per entry, declared relations first, and they count towards the response size cap (agents/teamai-recall.md:385):

    1. **[learnings] ledger-receipt-write-times-out-at-3s-2026-10-12-a1b2c3** — /…/learnings/ledger-receipt-write-times-out-at-3s-2026-10-12-a1b2c3.md
       The ledger receipt write times out at 3s; retry once.
       Related: → SUPERSEDES /…/team-repo/docs/payments-overview.md
       Confidence: high
    
    **Module: ledger-receipts** (pay)
    - Depends on: …
    - Related: ← MAPS_TO /…/team-repo/rules/payments.md
    

    Checks

    • teamai review --branch. It adds a relations check over every rule and doc in the materialized branch tree, as its other checks already do (src/review-branch.ts:1410-1438). It does not compare against a base.
      • It verifies that a target exists only for kinds that live on that branch: rules, docs, skills and teamwiki pages.
      • A learnings/ target is checked for shape only, because learnings live on teamai-learnings.
      • Exit status works as today: non-zero when the review finds a fail (src/review-branch.ts:1548).
    • teamai contribute. It prints the same findings as warnings for the learning it publishes, and still publishes it. A target exists if it is in the team clone on disk (rules, docs, skills, teamwiki) or in the learnings roots.

    Example

    The team repo (main) and the learnings branch:

    rules/payments.md
    docs/payments-overview.md
    skills/release/SKILL.md
    teamwiki/evidence/code/pay/modules/ledger-receipts.md
    learnings/ledger-receipt-write-times-out-at-3s-2026-10-12-a1b2c3.md   (teamai-learnings)
    
    <!-- rules/payments.md -->
    ---
    related:
      MAPS_TO: teamwiki/evidence/code/pay/modules/ledger-receipts.md
      REFERENCES: skills/release
    ---
    Every payment goes through ledger receipts; no direct writes to ledger.
    The flow is in [the overview](../docs/payments-overview.md).
    <!-- learnings/ledger-receipt-write-times-out-at-3s-2026-10-12-a1b2c3.md -->
    ---
    title: "Ledger receipt write times out at 3s"
    author: ana
    date: 2026-10-12
    tags: [payments, ledger, troubleshooting]
    related:
      SUPERSEDES: docs/payments-overview.md
    ---
    The receipt write times out at 3s; retry once.

    Recall output for this example. Lines marked + are new; paths and scores are illustrative:

     [1/3] [learnings] Ledger receipt write times out at 3s [workspace]
     Author: ana | Date: 2026-10-12 | Score: 6.2
     Tags: payments, ledger, troubleshooting
     File: /home/ana/.teamai/worktrees/acme/learnings/ledger-receipt-write-times-out-at-3s-2026-10-12-a1b2c3.md
    +Related: → SUPERSEDES /home/ana/proj/.teamai/team-repo/docs/payments-overview.md
    
     [2/3] [rules] payments [workspace]
     Author: unknown | Date: unknown | Score: 5.1
     File: /home/ana/proj/.teamai/team-repo/rules/payments.md
    +Related: → MAPS_TO /home/ana/proj/.teamai/team-repo/teamwiki/evidence/code/pay/modules/ledger-receipts.md
    +Related: → REFERENCES /home/ana/proj/.teamai/team-repo/skills/release/SKILL.md
    +Related: → REFERENCES /home/ana/proj/.teamai/team-repo/docs/payments-overview.md
    
     [3/3] [docs] ledger-receipts [workspace]
     Author: unknown | Date: unknown | Score: 5.0
     File: /home/ana/proj/.teamai/team-repo/teamwiki/evidence/code/pay/modules/ledger-receipts.md
    +Related: ← MAPS_TO /home/ana/proj/.teamai/team-repo/rules/payments.md
     Snippet: …

    If pay is withheld for this directory, hit 3 does not appear, and the rule's MAPS_TO line does not appear either.

    A learning published with a declaration outside the table, and a typo:

    related:
      SUPERSEDES: rules/payments.md
      REFERENCES: docs/payment-overview.md
    $ teamai contribute --file /tmp/ledger-timeout.md --title "Ledger receipt write times out at 3s"
    ⚠ related: a learning cannot SUPERSEDES a rule (rules/payments.md). Use CONFLICTS_WITH; this relation is ignored.
    ⚠ related: REFERENCES docs/payment-overview.md names no team asset; this relation is ignored.
    …
    

    The learning is published anyway, and recall shows neither relation.

    teamai review --branch fix/payments, where the branch changes the rule's frontmatter to:

    related:
      GOVERNS: teamwiki/evidence/code/pay/modules/ledger-receipts.md
      IMPLEMENTS: docs/payments-overview.md
      REFERENCES: docs/payment-overview.md
      ✖ [relations] rules/payments.md: "GOVERNS" is not a relation. Use MAPS_TO, REFERENCES, SUPERSEDES or CONFLICTS_WITH.
      ✖ [relations] rules/payments.md: IMPLEMENTS relates code to code and cannot be declared on a rule. Use MAPS_TO, REFERENCES, SUPERSEDES or CONFLICTS_WITH.
      ! [relations] rules/payments.md: REFERENCES docs/payment-overview.md names no team asset on this branch.
    

    Acceptance criteria

    Definition of done

  2. Walternater commented on Oct 31, 2026

    @Walternater
    ContributorAuthor

    I'd like to pick up the first slice from the triage comment above: declared relations via a related: frontmatter block, Related: lines on recall hits, and the relations check in teamai review --branch / warnings in teamai contribute.

    I'll implement strictly to the spec in the triage comment (vocabulary table, direction convention, visibility rules, unchanged ranking, cap of 5, malformed-input matrix) and the acceptance criteria listed there. Starting now; PR to follow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions