Skip to content
DocsTypes

PluginsEarly

Types

The types the elements, events and methods use, as plugin.d.ts declares them.

From the plugin interface of gr 0.2.16 (API 0.1, 0.2, 0.3). gr plugin api types prints it on your machine.

Json

            type Json = null | boolean | number | string | Json[] | { [k: string]: Json }
          

Tone

A role of the person's theme; a plugin never names a colour

            type Tone = "default" | "bright" | "muted" | "faint" | "accent" | "success" | "warning" | "error"
          

IconName

            type IconName = "close" | "check" | "plus" | "minus" | "more" | "up" | "down" | "overview" | "search" | "gear" | "send" | "architecture" | "graph" | "agents"
          

Pos

A place in a document: line counted from 0, and column from 0 in UTF-16 code units, as a JavaScript string counts. Every line and column the interface carries counts so

            interface Pos {
  line: number;
  column: number;
}
          

Context

Sent by the editor with every event that has one; file and selection text only with fs:read:workspace and for files inside the root; file.version (0.2) is the open document's version, what an edit names; file.line and file.column are the cursor's, counted as a Pos is; file.top and file.bottom are the first line on screen and the last, both shown, from 0; node is the node a node's page shows, the one the architecture view is on, or the map's selected node, and absent in a code view

            interface Context {
  seq: number;
  at: number;
  root: string;
  surface: "map" | "architecture" | "agents" | "agent" | "code" | "node" | "terminal" | "change" | "plugin" | "settings" | "empty";
  mode: "normal" | "insert" | "visual" | "visual_line" | "visual_block" | "prompt" | "command";
  pane: string;
  file?: { path: string;
  line: number;
  column: number;
  text: string;
  top: number;
  bottom: number;
  dirty: boolean;
  version?: number;
  selection?: { from: Pos;
  to: Pos;
  text: string;
  truncated?: true } };
  node?: string;
  selection: string[];
  agent?: string;
  view?: { view: string;
  item?: string };
  theme: { name: string;
  dark: boolean };
}
          

Filter

Narrows a handler to one of the plugin's commands, views, lists, pickers, (0.2) tools or (0.2) mention sources, or to paths matching a glob

            interface Filter {
  command?: string;
  view?: string;
  list?: string;
  picker?: string;
  path?: string;
  tool?: string;
  source?: string;
}
          

Attachment

A file inside the root, and with lines the first line of it and the last, both included, counted from 0; text (0.2) needs agents:write, since it is written into the next message the person sends, and is at most 64 KiB

            type Attachment = { node: string } | { file: string; lines?: [number, number] } | { agent: string } | { text: string }
          

Segment

            interface Segment {
  text: string;
  icon?: IconName;
  tone?: Tone;
  command?: string;
}
          

Badge

            interface Badge {
  text: string;
  tone?: Tone;
}
          

SelectItem

            interface SelectItem {
  label: string;
  detail?: string;
  key?: string;
}
          

Entry

Open is where Enter or a click on the entry goes, with line counted from 0

            interface Entry {
  key: string;
  label: string;
  detail?: string;
  aside?: string;
  icon?: IconName;
  tone?: Tone;
  open?: { path: string;
  line?: number } | { node: string } | { agent: string };
}
          

GraphNode

Rank is how much the node matters in an overview of the whole graph, from 0 to 1 among all of its nodes, and is absent (never 0) until the workspace has been ranked; tier is how finished the node is: stub (structure nobody has described yet), labeled (a real name, no description) or described. tags (since 0.2) are the node's authored and derived tags; line is the node's first line in its file, counted from 0

            interface GraphNode {
  id: string;
  name: string;
  kind: string;
  path?: string;
  line?: number;
  description?: string;
  parent?: string;
  rank?: number;
  tier?: string;
  tags?: string[];
}
          

Neighbor

            interface Neighbor {
  node: GraphNode;
  edge: string;
  direction: "in" | "out";
}
          

Agent

State is one of starting, running, working, waiting (on the person; attention says for what), couldnt_start, open_elsewhere, archived, asleep and stopped; activity is what the agent is doing right now in words ("Editing src/server.go"), when its harness says; absent between turns. startedBy (0.2) is "plugin:<name>" for an agent a plugin started

            interface Agent {
  id: string;
  name: string;
  state: string;
  harness: string;
  root: string;
  worktree?: string;
  attention?: string;
  started?: number;
  activity?: string;
  startedBy?: string;
}
          

DirEntry

            interface DirEntry {
  name: string;
  dir: boolean;
  size: number;
}
          

Stat

            interface Stat {
  size: number;
  dir: boolean;
  modified: number;
}
          

ExecResult

            interface ExecResult {
  code: number;
  stdout: string;
  stderr: string;
  truncated: boolean;
  ms: number;
}
          

FetchResult

            interface FetchResult {
  status: number;
  headers: Record<string, string>;
  body: string;
  truncated: boolean;
}
          

TranscriptBlock

One piece of an agent's conversation, oldest first: what the person or a plugin wrote to it (role user), what it answered (assistant), or what its CLI said (notice). kind text is words; tool is a tool it called, tool its name and text its arguments in one line, never what came back; shell is a command the person ran in it, text the command only; image is a picture, text empty. at is when its turn began, in ms since 1970. Each text is cut at 4 KiB (cut: true)

            interface TranscriptBlock {
  role: "user" | "assistant" | "notice";
  kind: "text" | "tool" | "shell" | "notice" | "image";
  text: string;
  tool?: string;
  at: number;
  cut?: true;
}
          

Since API 0.2.

SecretSetting

What $.settings.get and $.settings.all answer for a secret setting: whether the person entered it, never its value. Declared in plugin.toml as [settings.<key>] kind = "secret", with no default: host (one host [allow] net names, never a wildcard or any) and header (Authorization, X-Api-Key) put it in that header of each $.net.fetch addressed to that host, and format ("Bearer {}"; the value alone when not given) says where it goes in the header; an [[mcp]] server's env (env = { GITHUB_TOKEN = "<key>" }) gives it to that server in its environment. The person enters it with gr plugin secret set <plugin> <key> on a terminal; the daemon keeps it in the OS keychain (never config.toml), sends it only there, drops it on a redirect to another host, and takes it out of an answer that echoes it. The settings event says when it is set or cleared. A fetch to its host that sets its header itself is refused (net.secret_header). Tests have no secrets: t.fixtures({ settings: { <key>: { set: true } } }) says one is set

            interface SecretSetting {
  set: boolean;
}
          

Since API 0.2.

Worktree

A worktree of the root's repository: upstream is the branch it is measured against and lands into, ahead and behind count commits against it; current is the root's own

            interface Worktree {
  path: string;
  branch?: string;
  head: string;
  upstream?: string;
  ahead?: number;
  behind?: number;
  current: boolean;
  locked?: boolean;
}
          

Since API 0.2.

GitChange

A path of the root's working tree that differs from HEAD, as git status says; from is a renamed path's old one

            interface GitChange {
  path: string;
  status: "added" | "modified" | "deleted" | "renamed" | "untracked";
  from?: string;
}
          

Since API 0.2.

TextEdit

Text from one place of a document to another replaced: positions in lines from 0 and columns from 0 in UTF-16 code units, as a JavaScript string counts

            interface TextEdit {
  from: Pos;
  to: Pos;
  text: string;
}
          

Since API 0.2.

DocInfo

A document open in an editor of the root: its version rises with every change; tooLarge is one listed without text (over 8 MiB, or past the 64 MiB a root mirrors)

            interface DocInfo {
  path: string;
  version: number;
  language: string;
  dirty: boolean;
  eol: "lf" | "crlf";
  tooLarge?: true;
}
          

Since API 0.2.

Doc

A document and its whole text, lines ending in \n whatever eol says

            type Doc = DocInfo & { text: string }
          

Since API 0.2.

What a menu a right click opened is about, the one argument of a command run from a plugin's [[menus]] entry: {node} for a card, a box or a node's page; {agent} for an agent or its mark; {path, line, column, selection?} for code, with line from 0 and column in UTF-16 code units (contract C1) at the cursor, and selection the selected text only when the plugin holds fs:read:workspace (the daemon takes it out otherwise); {} at the other places. An entry is declared in plugin.toml as [[menus]] place (card, map, box, atlas, agent, mark, agents, composer, code, terminal, node, pane or tab), command (one of the plugin's own), title (at most 40 characters) and when (a context clause, contract C4: the entry shows only where it holds when the menu opens). Entries show after the editor's own rows, under the plugin's name, each with the keys bound to its command

            type MenuTarget = { node: string } | { agent: string } | { path: string; line: number; column: number; selection?: string } | Record<string, never>
          

Since API 0.2.

One entry of a row's own menu (the menu prop of item and node): title is what it says, command one of the plugin's own, and args what that command is run with, else [{view, key}], the view and the row's key. A right click on a row with a menu selects it and opens these; on one without, the pane's menu opens

            interface MenuEntry {
  command: string;
  title: string;
  args?: Json[];
}
          

Since API 0.2.

ToolAnswer

What a tool handler answers the agent that called it: words (text), or a value it reads as JSON (json). At most 64 KiB, the json as encoded (tool_answer_bytes); text holds no control character but newlines and tabs (a \r\n is taken as a newline), since the agent's harness shows it on a terminal. To refuse a call, throw: the agent reads the error's message

            type ToolAnswer = { text: string } | { json: Json }
          

Since API 0.2.

MentionEntry

One entry of a mention source: key (unique in the answer) is what mention.pick names, label what the composer's @ list shows, detail a few words after it, attach what choosing it attaches to the message as a chip naming the plugin (an Attachment: a node of the graph, a file inside the root with lines, an agent of the roster, or text, which needs agents:write). The daemon leaves out an entry it would not attach, and says which and why in the plugin's log (mention.entry); the others show

            interface MentionEntry {
  key: string;
  label: string;
  detail?: string;
  attach: Attachment;
}
          

Since API 0.2.

Decoration

A mark inside code that is not its text, in one of a plugin's [[decorations]] sets: a sign in the gutter (at most 2 characters, or an icon), an underline, a tinted range or tinted whole lines, words after a line's end (at most 120 characters), words inside a line (an inlay, at most 40), or a line above a line (a lens, at most 120, which runs one of the plugin's own commands with args [{path, line}] when pressed). Lines and columns count from 0, columns in UTF-16 code units; detail, at most 1 KiB, shows when the caret or the pointer rests on the mark. The editor cuts longer words and decides which marks show when room is short

            type Decoration = { kind: "sign"; line: number; text?: string; icon?: IconName; tone?: Tone; detail?: string } | { kind: "underline"; from: Pos; to: Pos; style?: "straight" | "wavy" | "dotted"; tone?: Tone; detail?: string } | { kind: "tint"; from: Pos; to: Pos; tone: Tone; lines?: boolean; detail?: string } | { kind: "eol"; line: number; text: string; tone?: Tone; detail?: string } | { kind: "inlay"; at: Pos; text: string; tone?: Tone; side?: "before" | "after"; detail?: string } | { kind: "above"; line: number; text: string; tone?: Tone; command?: string; detail?: string }
          

Since API 0.2.

GraphCreate

A node to create in this workspace. kind defaults to module; parent is a node of this root. Tags follow the MCP writer's authored-tag rule.

            interface GraphCreate {
  parent?: string;
  kind?: string;
  name: string;
  description?: string;
  tags?: string[];
}
          

Since API 0.2.

GraphPatch

Only these fields change. Authored tags such as user: travel with the repository; bare tags such as todo stay derived and may be reapplied after graph.changed.

            interface GraphPatch {
  name?: string;
  description?: string;
  addTags?: string[];
  removeTags?: string[];
}
          

Since API 0.2.

Diagnostic

One thing a language server says of a file of the root: path is within the root, slash-separated; from and to are where, as a Pos (lines from 0, columns from 0 in UTF-16 code units); severity is 1 error, 2 warning, 3 information, 4 hint, and absent when the server did not say; code and source are the server's own words for the rule and for who found it; tags are the protocol's (1 unnecessary, 2 deprecated); server is the name of the server that said it

            interface Diagnostic {
  path: string;
  from: Pos;
  to: Pos;
  severity?: 1 | 2 | 3 | 4;
  code?: string;
  source?: string;
  message: string;
  tags?: number[];
  server: string;
}
          

Since API 0.2.

DocSymbol

A symbol a language server finds in a file: kind is the protocol's SymbolKind (5 class, 6 method, 12 function, 13 variable, 23 struct and the rest); range is the whole symbol, selectionRange its name, both from and to as a Pos; children are the symbols inside it. A server that answers a flat list gives symbols with no children, range and selectionRange the same, and the name of what holds each as its detail

            interface DocSymbol {
  name: string;
  detail?: string;
  kind: number;
  range: { from: Pos;
  to: Pos };
  selectionRange: { from: Pos;
  to: Pos };
  children?: DocSymbol[];
}
          

Since API 0.2.

HarnessSetup

What one coding agent (Claude Code or Codex) loads when it starts in the root by one launch path (gr, the way Graphide and gr claude / gr codex start it, or plain, the bare CLI), and which layer each piece came from. Names, paths, sizes and a few setting values only: never a credential file, an MCP server's env or headers, a hook's environment, or an account's fields. layers are in precedence order (0 wins); instructions in load order; startupTokens estimates what loads at session start (four bytes a token); unreadable lists files found and not read, truncated each walk that stopped at its bound

            interface HarnessSetup {
  harness: "claude-code" | "codex";
  launch: "gr" | "plain";
  root: string;
  config_dir?: string;
  layers: SetupLayer[];
  instructions: SetupInstruction[];
  skills: SetupItem[];
  subagents: SetupItem[];
  commands: SetupItem[];
  hooks: SetupHook[];
  mcp: SetupMCP[];
  settings: SetupSetting[];
  sources: SetupSources;
  checks: SetupCheck[];
  startup_bytes: number;
  startup_tokens: number;
  unreadable?: { path: string;
  reason: string }[];
  truncated?: string[];
}
          

Since API 0.2.

SetupLayer

A place pieces come from: managed, cli (what the launch passes), local, project, user, profile (Codex's), launch (the launch's own flags, each flag with the path it names; an inline text as its size, never the text; a Codex -c as its key, never its value), plugin-dir, mcp-config, plugin, memory, import

            interface SetupLayer {
  id: string;
  name: string;
  path?: string;
  present: boolean;
  precedence: number;
  flags?: { name: string;
  value?: string }[];
}
          

Since API 0.2.

SetupInstruction

An instruction file (CLAUDE.md, AGENTS.md, a rule, an @import, the memory index): always is loaded at session start (false for a path-scoped rule), missing an @import naming a file that is not there, mentions the skills it names, generated the agent-config fragment it is rendered from

            interface SetupInstruction {
  path: string;
  name: string;
  kind: string;
  layer: string;
  order: number;
  bytes: number;
  tokens: number;
  always: boolean;
  imported_by?: string;
  missing?: boolean;
  mentions?: string[];
  generated?: string;
}
          

Since API 0.2.

SetupItem

A skill, subagent or command: shadowed when one of the same name in a winning layer hides it; scripts the files a skill ships beside its SKILL.md; last_used when a session in the root last called the skill (seconds since 1970, Claude Code only)

            interface SetupItem {
  name: string;
  path: string;
  layer: string;
  bytes?: number;
  shadowed?: boolean;
  scripts?: string[];
  mentions?: string[];
  generated?: string;
  last_used?: number;
}
          

Since API 0.2.

SetupHook

A hook: its event and matcher and what it runs, as the program and the script it names, never the command line's arguments or environment; found says whether that exists (absent when it cannot be told)

            interface SetupHook {
  event: string;
  matcher?: string;
  program?: string;
  script?: string;
  layer: string;
  path: string;
  found?: boolean;
  generated?: string;
}
          

Since API 0.2.

SetupMCP

An MCP server: its name, transport and program or host, never its env, headers or arguments

            interface SetupMCP {
  name: string;
  transport?: string;
  program?: string;
  host?: string;
  layer: string;
  path: string;
  found?: boolean;
  shadowed?: boolean;
}
          

Since API 0.2.

SetupSetting

A setting worth seeing (the permission mode, model, effort and a few others): the value that wins and the layer that set it, and every layer's value; unknown when the winner cannot be told

            interface SetupSetting {
  name: string;
  value?: string;
  layer?: string;
  path?: string;
  unknown?: boolean;
  values?: { layer: string;
  path: string;
  value: string }[];
}
          

Since API 0.2.

SetupSources

The agent-config checkout and profile that generate the setup's files, when there is one: each fragment (a profile's source file) and the files it renders, each same, rendered (substituted, so not compared), differs (edited by hand), stale (the fragment changed after the last sync) or missing

            interface SetupSources {
  agent_config?: string;
  profile?: string;
  profile_from?: string;
  fragments?: { kind: string;
  name: string;
  path: string;
  flows_to?: { target: string;
  path: string;
  state: "same" | "rendered" | "differs" | "stale" | "missing" }[] }[];
  targets?: { name: string;
  path?: string;
  present: boolean }[];
}
          

Since API 0.2.

SetupCheck

A problem a check found: drift (a generated file edited, stale or missing), parity (a skill, MCP server or hook event one harness has and the other lacks), broken (a named skill, an import or a hook's or server's program that is not there), unused (a skill nothing names or called in 30 days), size (what loads at start is over the budget), permission-mode (a layer's mode a higher layer replaced). related names the other side: the fragment to edit, the other harness, the layer that won

            interface SetupCheck {
  kind: "drift" | "parity" | "broken" | "unused" | "size" | "permission-mode";
  severity: "warn" | "info";
  subject: string;
  path?: string;
  layer?: string;
  detail: string;
  related?: string[];
}
          

Since API 0.2.

SetupLayerState

The Agent setup layer of the root's graph: on while some holder keeps it, with how many hold it and its node and edge counts

            interface SetupLayerState {
  root: string;
  on: boolean;
  holders: number;
  nodes: number;
  edges: number;
}
          

Since API 0.2.

These docs describe Graphide 0.2.16, the latest release. Something wrong or missing? Tell us onDiscord or at hello@graphide.com.