Connect
Writing a role
Follow this page from top to bottom and you end with a working role in your graph that an assistant can be called as. Each step fills in one or two properties.
Before you start
- An assistant connected to Vinc over MCP (Connect over MCP), or a write key (
vinc_sk_) if you will write from code. - Check the four default roles first (Agents). If one is close to what you want, change it instead of writing a near copy.
As the example, this page builds a release notes writer: a role that drafts release notes from merged pull requests and leaves publishing to a person.
1. Write the job in one sentence
Start with mission. One role is one job that one owner could answer for. If you need "and" twice to describe it, it is probably two roles.
| mission | |
|---|---|
| Good | Write the release notes for a tagged version from its merged pull requests, in the house style, and leave them as a draft for review. |
| Too broad | Handle releases. |
| Two jobs | Write the release notes, deploy the build and announce it. |
Write the role in English, as GRAPH.md asks. Say what the role produces and where the work stops ("leave them as a draft"). Copy the same sentence into one_liner; hosts show it in the role list.
2. Pick the seat
tier says what kind of seat the role takes. Pick the one that matches what the role leaves behind.
| If the role… | tier |
|---|---|
| hands out work and collects reports | orchestrate |
| changes files or makes something | execute |
| checks someone else's work and never edits it | verify |
| merges, deploys or tags a release | deliver |
| writes what others read, or tidies the graph | knowledge |
The release notes writer makes a file, so it is execute. A role that only reviews the notes would be a separate verify role: one seat should not both write and approve the same work.
3. Name it and file it
| Field | What to write | Example |
|---|---|---|
id | concept:agent- plus a short name in lowercase letters, digits and hyphens. agent-… becomes the prompt name. | concept:agent-release-notes |
type | Always concept. Other types do not keep properties. | concept |
title | The job name. Do not start it with "Agent role:". | Release notes writer |
domain | agent, or one level below it such as agent/release. Deeper roles do not show up as prompts. Roles that older spaces keep under vinc/agent are read too. | agent |
tags | Optional. agent, the tier and role make roles easy to filter. | ["agent", "execute", "role"] |
4. Draw the lines
never is what the role must not do at all. person_only is a step that has to happen, but a person takes it. Both are lists.
| Example | |
|---|---|
never | publish the notes, describe a change that is not in a merged pull request |
person_only | publishing the release |
Write each item as something you could check afterwards. "Be careful" cannot be checked; "describe a change that is not in a merged pull request" can.
5. Choose the model level
rung is one of strongest, strong, fast and cheapest. Never write a model name here. Choose by how costly a wrong answer is, not by how big the job is.
- A wrong answer is expensive and hard to notice (a security review):
strongorstrongest. - A wrong answer is cheap to spot and fix (a draft a person reads anyway):
fast. - A mechanical check with a clear right answer:
cheapest.
Release notes are a draft a person reviews, so fast. Which model each level uses is on Roles and teams.
6. Give it what it needs
| Key | What it is for | Example |
|---|---|---|
reads | Documents to read before the first edit, in order. Use document ids. | ["doc:release-notes-style"] |
gates | Checks that must pass before the work is handed over. | ["every entry links its pull request"] |
test_command | A command to run as the check, if there is one. | npm test |
repos, paths | Where the role works. The assistant stays inside them. | ["my-app"], ["CHANGELOG.md"] |
writes_graph | What it records in Vinc when done: episode, record, decision. | ["episode"] |
Put the house style in a document and list it in reads, rather than pasting the style into mission. Then several roles can share it, and changing the document changes every one of them.
7. Limit its tools
disallowed_tools: tools the host must not give this role. Averifyrole should listEdit,WriteandNotebookEdit.tools: tools or MCP servers the job needs. It is a list of what to have ready; the role returns the work if one is missing.isolation:worktreegives the role its own copy of the repository in Claude Code.
These are instructions to the host. Vinc does not block a tool by itself; the host has to apply the list.
8. Put it in a team (optional)
team, team_role (lead, coordinator or member) and job_title group roles in the app's Agent view. The order between roles is a link: prerequisite_of when one must finish before the other starts, relates_to for roles that work side by side. More on Roles and teams.
The whole role
Steps 1 to 7 together make this node. Lists stay JSON arrays: a single string is read one character at a time.
[
{
"id": "concept:agent-release-notes",
"type": "concept",
"title": "Release notes writer",
"domain": "agent",
"tags": [
"agent",
"execute",
"role"
],
"one_liner": "Write the release notes for a tagged version from its merged pull requests, in the house style, and leave them as a draft for review.",
"props": {
"mission": "Write the release notes for a tagged version from its merged pull requests, in the house style, and leave them as a draft for review.",
"tier": "execute",
"rung": "fast",
"never": [
"publish the notes",
"describe a change that is not in a merged pull request"
],
"person_only": [
"publishing the release"
],
"reads": [
"doc:release-notes-style"
],
"gates": [
"every entry links its pull request",
"no entry is longer than two sentences"
],
"repos": [
"my-app"
],
"paths": [
"CHANGELOG.md"
],
"disallowed_tools": [
"Bash"
],
"writes_graph": [
"episode"
]
}
}
]
9. Add it to Vinc
Choose one of four ways.
From 0.9.6 the desktop and web app have a form for this. Open Agent in the top row of the sidebar and press + above the list. The New Agent role sheet asks for the job name, the name (id), what it does, the seat, the model level, what it must never do, what a person does, and a team if you want one. Press Create, and the role is filed under the agent topic and shows in View and the tree straight away.
- Job name The title of the role.
- Name (id) Lowercase letters, digits and hyphens. The line below shows the id it becomes,
concept:agent-…(step 3). - What it does The role's job in one sentence (step 1).
- Seat Picked by what the role leaves behind (step 2). The line below changes with the choice.
- Model level Picked by how costly a wrong answer is (step 5).
- Create Checks that the name is free, then saves. If the role rules flag something, the role is still saved and the sheet lists what to fix.
The sheet does not take what the role reads or which tools it may use (steps 6 and 7). Add those afterwards by asking an assistant, or write the whole role another way. The demo above does not save.
Paste a request like this into an assistant connected to Vinc. It reads GRAPH.md, checks for an existing role, writes it and reads it back.
Read this graph's GRAPH.md with vinc_conventions first.
Then create an agent role in Vinc:
- id concept:agent-release-notes, topic agent, title "Release notes writer"
- mission: Write the release notes for a tagged version from its merged
pull requests, in the house style, and leave them as a draft for review.
- tier execute, rung fast
- never: publish the notes; describe a change not in a merged pull request
- person_only: publishing the release
- reads: doc:release-notes-style
Search for an existing role first, write it with vinc_ingest,
show me the warnings, then read it back with vinc_graph.
Send the node with vincs and a write key. When the role breaks a rule, the role is still stored, and the client raises VincPartialWrite with the warnings.
from vinc import VincClient, VincPartialWrite
vinc = VincClient(api_key="vinc_sk_...") # a write key
role = {...} # the node above
try:
vinc.ingest([role])
except VincPartialWrite as e:
print(e.result["warnings"]) # stored anyway; fix and resend
Without Python, send the same node to POST /v1/fragments (API), or as the nodes argument of the vinc_ingest MCP tool.
Put the node in a pack file and import it under Settings > Data > Import (Putting knowledge in). This suits adding several roles at once.
An import merges by id. A role in the pack with the same id as one in your graph replaces that role's properties whole, so check the ids first.
10. Check it
Read the warnings in the write result. The write checks each of these and still stores the role, so the warnings are the only thing that tells you something is off.
- The name after
concept:agent-has characters other than lowercase letters, digits and hyphens. - The topic is outside
agent(orvinc/agent), more than one level below it, or missing on a new role. - The title starts with "Agent role:".
- A required property is missing, or a new role has no properties.
tierorrunghas a value not listed above.- A list property is not a list.
one_linerandmissiondiffer.
Then call the role. In Claude Code, run /mcp__vinc__agent-release-notes; elsewhere ask the assistant to read concept:agent-release-notes. The assistant receives the role written out like this:
# Release notes writer
Tier execute, rung fast.
## Mission
Write the release notes for a tagged version from its merged pull requests, ...
## Surface
Repositories: my-app
- CHANGELOG.md
## Read before the first edit, in this order
1. doc:release-notes-style
## Gates that must pass before the pull request
- every entry links its pull request
- no entry is longer than two sentences
## Never
- publish the notes
- describe a change that is not in a merged pull request
## Only a person does this
- publishing the release
If something reads wrong here, fix the property it came from, not the text.
11. Change it later
- Properties are replaced whole on every write. Read the stored role first (
vinc_graphon its id), change what you need, and send all of it back. Anything you leave out is deleted. - When you change
reads,gates,neverorperson_only, write a decision in the same call: why, and what the value was before, linked to the role withabout.
{
"nodes": [
{
"id": "decision:agent-release-notes-add-breaking-gate",
"type": "decision",
"title": "Release notes flag breaking changes first",
"domain": "agent",
"props": {
"choice": "Add the gate 'breaking changes are listed first'.",
"reason": "Two releases buried a breaking change in the middle of the list.",
"replaced": "gates had two items"
}
}
],
"edges": [
{
"from": "decision:agent-release-notes-add-breaking-gate",
"to": "concept:agent-release-notes",
"type": "about",
"evidence": "Release 2.3 and 2.4 notes"
}
]
}
That way the role keeps its own history: open the role in the app and the decisions about it are linked right there.
All properties
| Property | Required | Value |
|---|---|---|
mission | yes | One sentence. |
tier | yes | orchestrate · execute · verify · deliver · knowledge |
rung | yes | strongest · strong · fast · cheapest |
never | yes | List |
person_only | yes | List |
reads | List of document ids, in order | |
gates | List | |
test_command | Text | |
repos | List | |
paths | List | |
tools | List | |
disallowed_tools | List | |
isolation | Text, such as worktree | |
delegate_rung | The rung for work it hands to a helper | |
team | Text | |
team_role | lead · coordinator · member | |
job_title | Text | |
writes_graph | List: episode, record, decision |