Vinc

Code and design, one graph

A token changes value, a screen changes shape, a line of code changes with it. The reason is one decision. Here is how to write that decision once and have the code and the design file both point at it, so that six months later "why is this colour so dark" gets the same answer from either side.

The example below is a fictional product, a dashboard called Northwind. Nothing in it is specific to a tool: the design file is any tool whose frames have addresses, the code is any language with comments. What joins them is one id.

1. Write the decision once

The accent colour measured 3.9:1 against the dark header, under the 4.5:1 threshold. Darkening one token brought it to 4.6:1. Four things go into the graph: the token concept, the screen concept, a record holding the measurement, and a decision that says why this value. The decision carries the design file's frame address in props.figma.

Four nodes and three edges travel in one vinc_ingest call. Both ends of an edge have to be in the same call to connect; an edge pointing at a node that is not there is dropped without an error, so read warnings in the response.

vinc_ingest
{
  "nodes": [
    { "id": "concept:northwind-accent-token", "type": "concept",
      "title": "Northwind accent token", "domain": "northwind/design/tokens",
      "one_liner": "The single accent colour, used for links and the primary action." },
    { "id": "concept:northwind-dashboard-header", "type": "concept",
      "title": "Northwind dashboard header", "domain": "northwind/design/screens",
      "one_liner": "The dark header bar that carries the title, the search box and the account menu." },
    { "id": "record:northwind-accent-contrast-measured", "type": "record",
      "title": "Measured 2026-09-01: the accent on the header background is 3.9:1, under the 4.5:1 threshold",
      "domain": "northwind/design/tokens",
      "props": { "subject_path": "northwind:tokens/design-tokens.json",
                 "measured_at": "2026-09-01", "measured_ref": "main 4f2c1e0",
                 "before": "3.9:1", "after": "4.6:1", "threshold": "4.5:1" } },
    { "id": "decision:northwind-accent-darkened-for-contrast", "type": "decision",
      "title": "The accent token is darkened one step so it clears 4.5:1 on the header",
      "domain": "northwind/design/tokens",
      "props": { "date": "2026-09-01",
                 "figma": "https://www.figma.com/design/FILEKEY/Northwind?node-id=214-88",
                 "chosen": "darken the accent token from #5B8DEF to #3D6FD1",
                 "rejected": ["lighten the header background: it is the brand dark",
                              "keep the value and add an outline: fails on the hover state"] } }
  ],
  "edges": [
    { "from": "record:northwind-accent-contrast-measured",
      "to": "concept:northwind-accent-token", "type": "relates_to",
      "evidence": "The measurement is of this token's value against the header." },
    { "from": "decision:northwind-accent-darkened-for-contrast",
      "to": "concept:northwind-accent-token", "type": "about",
      "evidence": "The decision changes this token's value." },
    { "from": "decision:northwind-accent-darkened-for-contrast",
      "to": "concept:northwind-dashboard-header", "type": "about",
      "evidence": "The header is the surface the contrast was measured on." }
  ]
}
A record about a file carries subject_path, measured_at and measured_ref: the three keys that let two measurements of the same file be compared. When the value changes again, do not delete this record; set its valid_until and attach a new one.

2. Point the design file at the graph, and the graph at the file

The decision holds the frame's address. The frame holds one line in its description: the decision's id. Neither tool knows about the other; the id is the seam. When a designer opens the frame and asks why the accent is this dark, that one line is the way to the answer.

This is all the frame description needs to say, and below it is the call that asks by that id. The answer brings the decision's reasoning, the measurement record attached to it, and which concepts the decision is about.

Frame description (in the design file)
  Header · accent darkened for contrast
  why: decision:northwind-accent-darkened-for-contrast

Ask the graph
  vinc_brief  question="decision:northwind-accent-darkened-for-contrast"
Address on the decision, id on the frame, not the other way round. A frame address changes when the file is moved; a node id in the graph does not. Let the thing that changes point at the thing that does not, and fewer links break.

3. Leave the claim in the code, hand the argument to the graph

Whoever edits the line needs to know what it does and what it must not break. That stays in the comment. Why it came to be this way, what was measured when, what was rejected: that lives in the graph, and the comment names the place by id. What used to be ten lines:

/* Accent colour. Was #5B8DEF until 2026-09-01. Measured against the
   header background it came out at 3.9:1, which fails the 4.5:1 AA
   threshold for normal text. We considered lightening the header
   instead, but that is the brand dark and the marketing site uses it
   too. We also tried keeping the value and adding an outline, which
   worked at rest but failed on the hover state. So the token itself
   was darkened one step to #3D6FD1, which gives 4.6:1. If you change
   this, re-measure against the header, not against white. See the
   design file, page Header, and the thread in #design from Sept 1. */
--color-accent: #3D6FD1;

becomes two. There is one form for the citation, [[id]], the same brackets for a document id and a node id, and the terminal reads it back with vinc doc get and vinc search.

/* Accent is darkened for contrast on the header. Re-measure against the
   header, not white, before changing it. why: [[decision:northwind-accent-darkened-for-contrast]] */
--color-accent: #3D6FD1;
Citations rot silently. When a node id changes or a document is re-entered under a new id, the comment points at nothing and nothing turns red. The remedy is a committed list of the ids the code cites, refreshed from the graph and committed alongside the code, with CI failing on any citation the list does not know. CI compares files to files, with no graph key: a graph key should never sit in CI.

4. Walk it in one call

Both sides end up asking one question: why is this value what it is, and what does it touch. vinc_path answers from the token concept, through the decision, to the screen concept in a single call.

vinc_path  from=concept:northwind-accent-token
           to=concept:northwind-dashboard-header

concept:northwind-accent-token
  ← about ─ decision:northwind-accent-darkened-for-contrast
             props.figma  https://www.figma.com/design/FILEKEY/Northwind?node-id=214-88
             attached     record:northwind-accent-contrast-measured  (3.9:1 → 4.6:1)
  ─ about → concept:northwind-dashboard-header

5. Which role reads what

Put Agent roles on this flow and each one has a place to read. The designer from the design pack reads the decision and its frame address, and writes a new decision when a value changes. The developer from the software pack follows the citation in the comment to the decision, and when the claim changes, fixes the graph first. The reviewer checks both sides' claims against the graph and labels each one cited, assumed or unsourced. All three write to the graph; none of them touches the file that holds the value.

What to keep straight

The assistant-side rules for this flow are what GRAPH.md fixes: search first, reuse ids, propose a topic rather than coin one mid-sentence.