# Graphide docs These docs describe Graphide 0.2.16. # Graphide docs Source: https://graphide.com/docs/ > How to install Graphide, map a project, connect your coding agents, and use the app, the gr command and plugins. Graphide runs coding agents on your projects and draws your code as a map you can read while they work. These docs cover the three parts you use: - **The app**, a native window for Linux and macOS. Projects and agents sit on the left, conversations and files in the middle, and the map of your code on the right. - **`gr`**, the command line tool. It installs and updates the app, signs you in, builds maps, and connects agents you run in a terminal, such as Claude Code, Codex and Cursor. - **Plugins**, written in TypeScript, which add commands, panels, pickers and map badges to the app, and tools for your agents. Behind both the app and `gr` runs one background service per user, the **daemon**. It keeps each project's map up to date as the code changes, and the app, `gr` and your agents all read the map through it. You do not start it yourself. ## Start here 1. [Install Graphide](/docs/install/): one command for `gr`, one for the app, then sign in. 2. [Map your first project](/docs/first-map/): open a folder and build its map. 3. [Connect your coding agent](/docs/agents/): give Claude Code, Codex or another agent the map, inside the app or in your own terminal. The short version, on Linux or macOS: ```sh curl -fsSL https://graphide.com/install.sh | sh gr app install gr login gr app open . ``` ## Find your way | You want to | Read | |---|---| | Learn the app's parts and windows | [A tour of the app](/docs/app/) | | Read and rearrange the map | [The map](/docs/app/map/) | | Run and steer agents in the app | [Agents in the app](/docs/app/agents/) | | See and accept what agents changed | [Review changes](/docs/app/review/) | | Look up a key | [Keys and mouse](/docs/app/keys/) | | Look up a `gr` command | [Command reference](/docs/cli/reference/) | | Install or write a plugin | [Using plugins](/docs/plugins/), [Write a plugin](/docs/plugins/write/) | | Know what leaves your computer | [Your code and data](/docs/privacy/) | | Fix something | [Troubleshooting](/docs/troubleshooting/) | ## For coding agents An agent asked to install Graphide for someone can follow [graphide.com/claude.md](/claude.md). The outline of these docs is at [/llms.txt](/llms.txt), and every page in one file is at [/llms-full.txt](/llms-full.txt). --- # Install Graphide Source: https://graphide.com/docs/install/ > Install the gr command line tool and the Graphide app, sign in, keep them up to date, and remove them. Graphide runs on **Linux on x86_64**, with a Vulkan driver, and on **macOS on Apple silicon**. Windows, Intel Macs and Linux on ARM are not supported yet. You install it in three steps. None of them needs root. ## 1. Install `gr` ```sh curl -fsSL https://graphide.com/install.sh | sh ``` This installs the `gr` command line tool, about 60 MB, into Graphide's data folder and links it as `~/.local/bin/gr`. The installer checks the download's SHA-256 before it unpacks anything. It needs `curl`, `awk`, `tar`, `mktemp`, and `sha256sum` or `shasum`, which most systems already have. On Linux it needs glibc: musl systems such as Alpine are not supported. If `~/.local/bin` is not on your `PATH`, the installer adds it in your shell's startup file (`~/.zshrc`, `~/.bashrc`, `~/.bash_profile` or fish's `conf.d`), between the lines `# >>> graphide gr >>>` and `# <<< graphide gr <<<`. Open a new terminal for it to take effect, or use the full path to `gr` that the installer prints on its last line. ## 2. Sign in ```sh gr login ``` Your browser opens on Graphide's sign-in page. Sign in with a provider, or create an account with your email. `gr login` waits until you are done. On a machine with no browser, such as an ssh session, `gr login` notices and prints an address and a code instead. Open the address on any computer, type the code and sign in there. `gr login --no-browser` asks for this on purpose. ## 3. Install the app ```sh gr app install ``` This downloads the Graphide app, about 80 MB, checks it, and installs it: - **macOS:** in Applications, as Graphide. - **Linux:** in Graphide's data folder, with a `graphide` command in `~/.local/bin` and an entry in your applications menu. Then open it on a project: ```sh cd ~/code/my-project gr app open . ``` You can also start it from your applications menu, or with `graphide` on Linux. The first time it opens a project it builds that project's map; see [Map your first project](/docs/first-map/). ### What the Linux installer checks On Linux, `gr app install` warns about anything the app will miss: | Warning | What to do | |---|---| | No Vulkan driver (`libvulkan.so.1`) | Install your GPU's Vulkan driver. On Ubuntu that is `mesa-vulkan-drivers`. Without it the window cannot draw. | | `bwrap` is missing | Install `bubblewrap` with your package manager. Agents and plugins run sandboxed with it. | | `git` is missing | Install git. Graphide needs it for projects. | | `~/.local/bin` is not on `PATH` | Add it, or start the app from the applications menu. | ### When the install fails `gr app install --json` prints one JSON object with `ok`, and an `error.code` when `ok` is false: | Code | Meaning | |---|---| | `not_signed_in` | Run `gr login`, then install again. | | `account_not_active` | Your account is waiting to be activated. [Your dashboard](/dashboard/) says where it stands. | | `no_native_build` | No build of the app is published for this machine yet. | | `unsupported_platform` | This machine is not one Graphide runs on. | | `checksum_mismatch`, `signature_invalid` | The download was damaged or did not verify. Run the command once more, and [tell us](/docs/troubleshooting/#report-a-bug) if it fails again. | | `download_failed`, `api_unreachable` | Graphide's servers could not be reached. Check your connection and try again. | | `app_running` | Quit Graphide first, or use `gr app update`. | | `busy` | Another install or update is running. | ## Updates Graphide tells you when an update is out and installs it for you: the app shows an Update button, and the update goes in when Graphide restarts. From a terminal: | Command | Does | |---|---| | `gr version` | Prints this build of `gr`, the daemon's, and whether a newer one exists. | | `gr app status` | Says which version is installed and whether a newer one is out. | | `gr app update` | Downloads the newest version and stages it for the next restart. `--apply` puts it in now; quit Graphide first. | | `gr app rollback` | Goes back to the version before the last update. | ## Where Graphide keeps things | | Linux | macOS | |---|---|---| | Settings (`config.toml`) | `~/.config/graphide/` | `~/Library/Application Support/Graphide/` | | Programs, records, saved chats | `~/.local/share/graphide/` and `~/.local/state/graphide/` | `~/Library/Application Support/dev.graphide.app/` | | Cache | `~/.cache/graphide/` | `~/Library/Caches/graphide/` | | A project's map | `.graphide/` inside the project | `.graphide/` inside the project | On Linux the folders follow `XDG_CONFIG_HOME`, `XDG_DATA_HOME`, `XDG_STATE_HOME` and `XDG_CACHE_HOME` when you set them. Your sign-in is kept in the system keychain, not in these files. ## Uninstall ```sh gr uninstall --dry-run # see what would go gr uninstall ``` `gr uninstall` removes Graphide's settings, your saved sign-in, the daemon's records, and the installed builds and saved chats in Graphide's data folder. It asks first; `-y` skips the question. It never touches the `.graphide/` folders inside your projects; delete those yourself if you want them gone. Then remove what is left outside those folders: - **macOS:** drag Graphide from Applications to the Bin. - **Linux:** remove `~/.local/bin/gr`, `~/.local/bin/graphide` and `~/.local/share/applications/graphide.desktop`. - Remove the `# >>> graphide gr >>>` block from your shell's startup file. If you connected a terminal agent with `gr harness install`, run `gr harness uninstall --all` before `gr uninstall` to take Graphide's part out of those projects' files. Removing Graphide from your computer does not delete what Graphide keeps on its servers. [Your code and data](/docs/privacy/) says how to delete that. --- # Map your first project Source: https://graphide.com/docs/first-map/ > Open a project, build its map, and keep the map up to date as the code changes. A project is a git repository on your computer. Graphide reads its code into a graph of its parts and how they join, and draws the map and the Architecture diagram from that graph. Your agents find their way by it too. ## Open a project In a terminal, from the project's folder: ```sh gr app open . ``` Or, in the app, click **Open a folder…** on the Welcome tab, choose **Add or open a project** in the command palette, or click the **+** beside Projects in the sidebar. The same place can clone a repository for you. Open the top of the repository, the folder that holds `.git`. Graphide finds the repository's top from any folder inside it. ## Build the map A project without a map shows **This project has no graph yet** on the right. Click **Build the graph**. The map is built on Graphide's servers. Before it builds anything, Graphide asks you to accept its terms and privacy policy, because the build keeps a copy of the project's code on its servers. Choose **Accept and build** on that card, or run `gr terms accept`. Until you accept, none of your code is kept, and everything else in the app works as before. [Your code and data](/docs/privacy/) says what is kept and how to delete it. While it builds, the card says **Building the graph** and the map fills in as it goes. It takes from under a minute to a few minutes on a large repository. You do not have to wait: start an agent now, and it works while the map is built. Once it is built, the map keeps itself current as the code changes, including changes your agents make and branches you switch to. ### Cards you may see instead | The card says | Why | |---|---| | **Waiting: you're using N of your M builds** | Your account builds a set number of maps at once. This one starts when another finishes. | | **Graphide's servers are full** | Every build slot is busy. Yours starts by itself. | | **Waiting for another init** | A build of the same project is already running. | | **Waiting for the internet** | Building needs the internet. The map already on this computer stays readable, and the build starts when the connection returns. | | **Waiting for approval** | Your account is not activated yet. The map appears by itself once it is. | | **Join** | The project's map already exists in the cloud, for example because a teammate built it. Joining copies it down instead of building it again. | ## From the terminal You can build and check maps without the app: ```sh gr init # build this project's map, with progress gr map # is the map of main and each worktree up to date? gr status # is the daemon serving this project? gr doctor # what is wrong, in plain words ``` `gr init` climbs to the repository's top, like the app. It asks before it maps a very large folder, your home folder, or a folder that holds several repositories, since those are rarely what you meant. `gr project new ` makes a new, empty project in `~/Projects/` and runs `git init` in it. `gr sync` brings a map back in step with the code by hand, and `gr clear` deletes a project's map so `gr init` can build it afresh. Neither is part of normal use. ## Leave parts of a project out Graphide maps what git tracks and skips what `.gitignore` leaves out. To skip folders that are committed but are not your code, such as fixtures, vendored libraries or sample apps, list them in the project's own `.graphide/config.toml`: ```toml [init] exclude = ["testdata/fixtures", "third_party", "examples"] ``` Paths are relative to the repository's top, with forward slashes. A change applies at the next build. ## Very large repositories A first build of a very large repository (tens of thousands of files, or millions of lines) can use a lot of memory on your computer. If it does, exclude the folders you do not work in, as above, and build again. Your plan also caps how large a codebase it maps; see [pricing](/pricing/). --- # Connect your coding agent Source: https://graphide.com/docs/agents/ > Give Claude Code, Codex, Cursor and other agents the map of your code, in the app or in your own terminal. Graphide gives a coding agent the map through an MCP server. With it the agent asks the map who calls a function, what a change would break, or where something is, in one call instead of a dozen searches. There are three ways to connect one. All of them need you signed in to Graphide (`gr login`). The agent itself runs on its own sign-in: what you use in Claude Code or Codex is billed by Anthropic or OpenAI. ## In the app Agents you start in the app, Claude Code or Codex, already have the map. Nothing to set up. See [Agents in the app](/docs/app/agents/). ## In your terminal, writing nothing ```sh gr claude # Claude Code gr codex # Codex ``` `gr claude` runs Claude Code with Graphide's hooks, permissions, MCP server and skill passed on its command line. `gr codex` runs Codex with Graphide's MCP server passed the same way. Neither writes anything to your project or to the agent's own settings, so there is nothing to undo. Every argument goes on to the agent, so `gr claude --resume` or `gr codex exec "…"` work as they would without `gr`. For the agents' own help use `gr help claude`, since `gr claude --help` prints Claude Code's. ## In your terminal, installed into the project For an agent you start some other way, or one `gr` does not launch, `gr harness install` writes the connection into the project: ```sh gr harness list # which agents are found here, and what is installed gr harness install cursor gr harness status cursor gr harness uninstall cursor # take Graphide's part out again ``` | Agent | Name | What it writes | |---|---|---| | Claude Code | `claude` | Hooks in `.claude/settings.local.json`, a skill, and the MCP server | | Codex | `codex` | A block in `AGENTS.md`. The MCP server is never written; run `gr codex` for it | | Cursor | `cursor` | `.cursor/mcp.json` and `.cursor/rules/graphide.mdc` | | Gemini CLI | `gemini` | `.gemini/settings.json` and a block in `GEMINI.md` | | OpenCode | `opencode` | `opencode.json` and a block in `AGENTS.md` | | VS Code (Copilot agent mode) | `vscode` | `.vscode/mcp.json` and a block in `.github/copilot-instructions.md` | | Windsurf | `windsurf` | Windsurf's MCP config for your user, and a block in `.windsurfrules` | Before it writes, `gr harness install` backs up each file it changes, and it adds the new MCP files to the repository's git exclude so you do not commit them by accident. It changes only Graphide's own part of a shared file such as `AGENTS.md`. If you are signed out it writes nothing. After installing, some agents need one more step, which `gr harness install` prints: - **Cursor:** `cursor-agent mcp enable graphide`, or turn the server on in Cursor's MCP settings. - **Gemini CLI and VS Code:** trust the workspace. - **Windsurf Enterprise:** turn MCP on in Cascade's settings. `gr harness uninstall --all` removes the connection from every project on this computer that has it. ## What the agent gets The MCP server answers from the map the daemon keeps. It has no tools for the shell, the web, git or editing files: the agent keeps using its own for those. If you sign out, its tools answer that they are locked and name `gr login`. The map's tools include: | Tool | Answers | |---|---| | `query` | A question about the code, as a small ranked slice of the map in one call | | `impact` | Who calls a symbol and what a change to it breaks, hop by hop with `file:line` | | `search_nodes` | Parts of the map by name, path or description | | `get_node_code` | One part's source | | `find_path` | Whether one part can reach another | | `similar` | Code that does something similar | | `resolve_location` | Which part of the map owns a `file:line` | | `get_node_diff` | What changed about a part between two revisions | | `switch_root` | Moves the session to another worktree of the same repository | | `report_issue` | Sends a Graphide bug the agent ran into to the Graphide team | Each agent starts with a small set of these, chosen for that agent, so the server costs little of its context. The same answers are on the command line, for you or for scripts: ```sh gr query "where are sessions refreshed" gr impact internal/auth/session.go:Refresh gr code internal/auth/session.go:Refresh gr outline internal/auth/session.go ``` See the [command reference](/docs/cli/reference/) for each. ## Another MCP client `gr mcp` is the server itself, over stdio, for any MCP client `gr harness` does not list. Point the client at `gr mcp` as a stdio server, started in the project's folder. It is not a command to run by hand. --- # A tour of the app Source: https://graphide.com/docs/app/ > The parts of the Graphide window, the three windows you can choose between, and how to find any command. ## The window - **The sidebar**, down the left, lists your agents by what each needs from you, with **New agent** across its top. A setting turns it into a list of your projects and their worktrees instead. - **The middle** shows the agent you chose, its conversation on top and the composer you write in underneath. A file or a terminal you open shows here too, in tabs. - **The right side** shows one part at a time, chosen in the bar at its top: the graph map, the Architecture diagram, files, source control, a browser, changes to review, and more. The menu bar holds File, Edit, View, Go, Graph, Agents, Review, Experimental and Help; **F10** opens it. The status bar at the bottom has a **Report bug** button that sends us a report with the logs we need. ## Find anything | Keys | Opens | |---|---| | Ctrl+K | **Search or ask**: files, symbols, agents and commands. Start with `?` to ask a question, answered with a map. | | Ctrl+P | Find a file or a part of the map | | Ctrl+Shift+P | Every command | | F1 | Help, which has a guide to each part of the app | The rest are in [Keys and mouse](/docs/app/keys/). ## Three windows Graphide comes in three windows. They show the same projects, agents and map, and differ in layout and keys. | Window | What it is | |---|---| | **Normal** | The default. An app: your projects and agents at the left, tabs in the middle, the map at the right, and keys that type. | | **Vim** | Vim's panes, modes and `:` commands, with the map beside your code. Everything is a few keys away. See [The Vim window](/docs/app/vim/). | | **Standard layout** | A layout with more buttons, where typing just types. | You choose between Normal and Vim on the tutorial's first step. To switch later, use Settings, Appearance, **Editor mode**, or the View menu's **Normal mode** and **Vim mode**. **Standard layout** is in the command palette. No key switches windows, so you cannot change by accident. A separate setting, **How keys behave**, lets one window use the other's typing: the Normal window with Vim's modes, for example. ## The tutorial The first time Graphide starts, a short tutorial walks you through the app on a bundled example project. It changes none of your code. It asks which window you want, which theme, and whether to sign in. You can skip signing in: everything on your computer works without an account, and you can sign in later from Projects. Building and updating maps needs a sign-in, since Graphide does both on its servers. ## Projects and worktrees Add a project with the **+** beside Projects, or **Add or open a project** in the command palette, which can also clone one. A **worktree** is another checkout of the same repository on a branch of its own, so several agents can work at once without touching each other's files. The small **+** on a project's row makes one: name the branch and choose what it starts from. A new agent can start in a new worktree of its own, too. ## Where to go next - [The map](/docs/app/map/): read your code as cards inside cards. - [Agents in the app](/docs/app/agents/): start, steer and answer agents. - [Review changes](/docs/app/review/): see what changed, on the map. - [Settings](/docs/app/settings/): themes, controls and the settings file. --- # The map Source: https://graphide.com/docs/app/map/ > Read your whole codebase as cards inside cards, move around it, rearrange it, and see the Architecture diagram drawn from it. The graph map draws your whole codebase as cards inside cards: folders hold files, files hold functions, and the lines between cards are calls and uses. It is the first part on the right of the window; **Ctrl+Shift+M** brings it back. ## Move around - **Zoom in to go deeper.** The wheel or a pinch zooms, about the pointer. - **Double click** a card to go into it. A **double middle click** shows the whole map. - **Drag** with the left or middle button to pan, or with two fingers on a trackpad. - **Click** selects a card. **Shift+click** adds or removes one, and **Shift+drag** draws a box that adds every card inside it. - **Ctrl+click** opens a card's code. With the keyboard, the arrows move between cards, **Enter** goes in and **Backspace** goes up. **Ctrl+F** searches the map. The full list is in [Keys and mouse](/docs/app/keys/#the-map). If you are used to another program's mouse, Settings, **Controls like**, maps the mouse to its habits: Onshape, SOLIDWORKS, Blender, AutoCAD, Autodesk Fusion, Figma, KiCad, Miro, Rhino or SketchUp. The **?** in the map's tools shows what each kind of line means. ## Ask about a card Right-click a card for its menu: - **Go in**, and **what it says**: the description of what the code does. - **Ask an agent about it.** - **Open its code.** - **What uses it** and **what it depends on**. - **Rename** it, or **copy its reference** to paste into a prompt. ## Rearrange it The map is yours to arrange. Drag a card to move it, hide it, describe it in your own words, put a new box inside it, group the cards you chose, or draw a line between two cards. A **box of ideas** holds whatever you put in it. **Ctrl+Z** undoes a change and **Ctrl+Shift+Z** redoes it, while the window is open. ## Agents on the map Your agents show on the map as marks, each wearing its own badge. Click a mark to follow that agent. Settings, **Show agents on the map**, turns the marks off. The **Presenter** is where an agent shows you something: a place on the map, a folder or a file, a setting or a web page. Turn on its **Auto-follow** switch to follow along as agents show you things. ## The Architecture diagram The Architecture diagram is the system map of your project: a box for each part, nested where one part owns another, and labelled lanes between them for how they talk. In the Normal window, **Ctrl+Shift+A** opens it. Right-click a box and choose **Show it on the graph** to go from the big picture to the functions underneath. --- # Agents in the app Source: https://graphide.com/docs/app/agents/ > Start Claude Code and Codex agents, steer them, answer what they ask, and keep several at work at once. An agent is Claude Code or Codex at work in one worktree of a project. Its page holds the conversation on top and the composer you write in underneath. Agents run on your own Claude Code or Codex sign-in. If an agent asks you to sign in, do it from Settings, **Connectors**, which signs you in to Claude Code and Codex and connects your clouds and machines. ## Start one Click **New agent** at the top of the sidebar, on a project's home, or on the **+** at the end of the tabs. **Ctrl+N** does the same. The new agent's page has two chips: - **Which agent:** Claude Code or Codex. Settings says which comes first. **Ctrl+;** changes it. - **Where it starts:** **This checkout**, or **A new worktree** of its own, so it works on its own branch without touching your files. **Ctrl+.** changes it. Write what you want and press **Enter**. ## Write to it | In the composer | Does | |---|---| | Enter | Sends, and you stay on this agent | | Alt+Enter | Sends, then opens the next agent that is waiting for you or is done | | Shift+Enter | A new line | | `@` | Names a file, a part of the map or another agent | | `/` at the start of a line | Lists the agent's own commands | | **+** | Attaches a file, a picture or a part of the map | | Alt+X, or the microphone | Voice typing: hold, speak, let go | Settings, under Agents, swaps Enter and Alt+Enter if you would rather Enter moved you on to the next agent. **Ctrl+L** asks an agent about what you have selected, and **Ctrl+Shift+L** adds the selection to the prompt you are writing. **Alt+P** picks the agent's model and effort. While an agent works and the composer is empty, **Send** becomes **Stop**, which ends its turn. A message you send while it works waits under the conversation for its turn. ## Answer it The sidebar is a to-do list: every agent, grouped by what it needs from you. A question or a permission request is answered right on its row, with **Allow**, **Always**, **Deny** or **Answer**. - **F8** jumps to the next request for you, and **Shift+F8** to the one before. - **Ctrl+Enter** on a finished agent with nothing written archives it and opens the next, so you can work through them like an inbox. - **Ctrl+M** snoozes an agent for half an hour, or for as long as Settings, **Snooze for**, says. - **Ctrl+E** switches to another agent by name. With notifications on, as they are at first, the app also tells you when an agent needs you. ## Its menu Right-click an agent, on its page or its row, for its menu: ask about it, its terminal, its model and effort, pause, stop, restart, fork the conversation, open its worktree, land its work, pin it to the top, snooze it, or archive it. Closing an agent's tab does not stop the agent. Stop it from its menu. ## Each agent's badge Every agent wears a coloured badge with its initial, the same everywhere: in the sidebar, on its tab, and on the map. A disc is Claude Code, a square is Codex, and a ring is any other kind. ## Terminals **Ctrl+`** opens the agent's terminal, and goes back to its page if you are already there. **Ctrl+Shift+`** opens a new terminal of your own. A program in a terminal gets every Ctrl key you press. Settings, **Open agents as**, can open agents in their terminal by default: the agent's own command line screen, as it runs. ## Several at once Give each agent a worktree of its own, and they can all work at once without touching each other's files. When one is done, **Land the agent's work** in its menu brings its worktree's changes home. [Review changes](/docs/app/review/) first shows you what it did. --- # Review changes Source: https://graphide.com/docs/app/review/ > See what your agents changed, drawn on the map, accept or reject it, and bring their work home. ## Changes to review **Changes to review**, on the right, lists what changed: your working tree, each agent's work, branches and merges. Choose one to see it drawn on the map, file by file, so you see where in the codebase a change landed before you read a line of it. In the Normal window, **Ctrl+Shift+R** opens it. The **Diffs** part keeps every past change, each drawn on the map the same way. ## Accept or reject an agent's changes In a file a Claude Code agent changed, accept or reject each change (a hunk) or the whole file, and undo the last one. A Codex agent's changes show on its page, but cannot be accepted or rejected there. Review them in Changes to review, or in a terminal. **Which agent wrote this** names the agent behind a line of code. ## Bring an agent's work home An agent that worked in a worktree of its own made its changes on that worktree's branch. **Land the agent's work**, in the agent's menu, brings its worktree's changes home. From a terminal, `gr worktree land` lands any worktree: it merges the worktree's branch into its base branch, pushes, removes the worktree and its branch, and brings the map up to date. `--no-push` keeps it on your computer, and `--dry-run` prints what it would do. On a conflict it decides nothing for you and prints the command that backs out. ## Source control **Source Control** lists what changed in the repository: the working tree first, then pull requests, branches, merges and commits. Click a row to see that change drawn on the map, file by file. It shows once you are signed in. It only reads: commit and push from a terminal, or ask an agent to. ## Tests The **Tests** part shows how your CI runs relate to your code: - **Runs** shows, for each run, how much of the code a change needed tested against how much its tests reached. - **Saved** shows what Graphide's test selection would have saved on your CI: hours, then dollars, then how many failing tests it would still have run. It needs GitHub connected; the part offers **Connect GitHub**. Both need you signed in. --- # Keys and mouse Source: https://graphide.com/docs/app/keys/ > The keys of the Normal window and Standard layout, on the map, in the composer, and the mouse on the map. These are the keys of the Normal window and Standard layout, where typing types. The Vim window's keys are in [The Vim window](/docs/app/vim/). On a Mac, Alt is Option. The app's menus and Settings, **Keyboard shortcuts**, show the key for each command as your copy has it. ## Everywhere | Keys | Does | |---|---| | Ctrl+K | Search or ask | | Ctrl+P | Find a file or a part of the map | | Ctrl+Shift+P | Every command | | Ctrl+Shift+F | Find in files | | Ctrl+R | Open a recent file or part of the map | | Ctrl+Shift+O | Go to a symbol in this file | | Ctrl+T | Go to a symbol anywhere | | Ctrl+O | Your projects: open, clone or start one | | Ctrl+, | Settings | | F1 | Help | | F10 | The menu bar | | Ctrl+Q | Quit | ## Agents | Keys | Does | |---|---| | Ctrl+N | New agent | | Ctrl+; | Which agent the new one is: Claude Code, Codex or a plugin's | | Ctrl+. | Where the new agent starts | | Ctrl+E | Switch agent | | Ctrl+B | Show or hide the agents | | Alt+S | The agents' list over the agent, or alone | | F8 and Shift+F8 | The next and the previous request for you | | Ctrl+M | Snooze an agent | | Alt+P | The agent's model and effort | | Alt+T | Step the agent's effort | | Alt+F | The agent's fast mode, on or off | | Ctrl+L | Ask an agent, with what is selected | | Ctrl+Shift+L | Add what is selected to the prompt | | Alt+X | Voice typing: hold, speak, let go | | Ctrl+\` | The agent's terminal, or back to its page | | Ctrl+Shift+\` | A new terminal | In the composer, **Enter** sends, **Alt+Enter** sends and opens the next agent that needs you, and **Shift+Enter** starts a new line. **Ctrl+Enter** on a finished agent with nothing written archives it and opens the next. ## Panes and tabs | Keys | Does | |---|---| | Ctrl+Tab and Ctrl+Shift+Tab | The next and the previous tab (also Ctrl+Page Down and Ctrl+Page Up) | | F6 and Shift+F6 | The next and the previous pane | | Ctrl+\\ | Split the pane, side by side | | Ctrl+W | Close the pane or tab | | Ctrl+Shift+M | The map | ### The Normal window's own | Keys | Does | |---|---| | Ctrl+Shift+N | New agent | | Ctrl+Shift+J | Search or ask | | Ctrl+Space | Switch agent | | Ctrl+Shift+R | Review changes | | Ctrl+Shift+A | The Architecture diagram | | Ctrl+Shift+E | Files | | Ctrl+Shift+G | Source control | | Ctrl+Alt+B | Show or hide the right side | | Ctrl+Shift+T | Reopen the tab you closed | In Standard layout, **Ctrl+Shift+G** opens the changes: the working tree, agents and branches. ## In code With a language server for the file's language: | Keys | Does | |---|---| | F12 | Go to the definition | | Shift+F12 | Find references | | F2 | Rename | | Alt+Enter | Code actions | | Alt+Shift+F | Format | ## The map | Keys | Does | |---|---| | Arrows | Move between cards | | Enter | Go into the card | | Backspace | Go up | | Tab and Shift+Tab | The next and the previous card beside this one | | Ctrl+F | Search the map; F3 and Shift+F3 for the next and previous match | | F12 | Open its code | | Shift+F12 | What uses it | | Alt+F12 | What it depends on | | Ctrl+F12 | Its implementations | | F2 | Rename | | Shift+F2 | Rewrite its description | | Insert | Add a card after this one | | Alt+Insert | Add a card inside this one | | Delete | Hide the card, or take a box apart | | Ctrl+G | Group the chosen cards | | Ctrl+Z | Undo | | Ctrl+Shift+Z or Ctrl+Y | Redo | | Ctrl+= and Ctrl+- | Zoom in and out | | Ctrl+0 | The whole map | ## The Architecture diagram | Keys | Does | |---|---| | Arrows | Move between boxes | | Enter | Go into the box | | Backspace | Go up | | Space | Open the box in place | | F12 | Its code | | Shift+F12 | Show it on the graph | | Ctrl+F | Search | ## The agents' list | Keys | Does | |---|---| | Up and Down | Move | | Enter | Press the row | | Right and Left | Open or fold a group | | Ctrl+Enter | Stop and archive | | Ctrl+F | Filter | | Alt+Up and Alt+Down | Move the agent up or down | ## The mouse on the map | Mouse | Does | |---|---| | Wheel, or a pinch | Zoom, about the pointer | | Left or middle drag | Pan | | Space and a left drag | Pan | | Two fingers | Pan; with Ctrl, zoom | | Click | Select a card | | Shift+click | Add a card to the selection, or take it out | | Shift+drag | Draw a box that adds cards | | Ctrl+click | Open the card's code | | Double click | Go in or out | | Double middle click | The whole map | Settings, **Controls like**, maps the mouse to the habits of Onshape, SOLIDWORKS, Blender, AutoCAD, Autodesk Fusion, Figma, KiCad, Miro, Rhino or SketchUp instead. --- # The Vim window Source: https://graphide.com/docs/app/vim/ > Vim's panes, modes and colon commands, with the map beside your code, and the map's own Vim keys. The Vim window is Vim's panes, Vim's modes and `:` commands, with the map beside your code. Choose it on the tutorial's first step, in Settings under Appearance, **Editor mode**, or with **Vim mode** in the View menu. Your choice is kept. ## The leader The leader key is **Space**, unless you change it. It opens a menu of everything, and each row shows the next key, so you can find a command by reading and learn its keys as you go. ## Commands and options `:` commands work as in Vim. `:set` changes an option for this session only; Settings saves it for good. Options such as `number`, `relativenumber`, `scrolloff`, `ignorecase` and `smartcase` can also be set for one project in its `.graphide/config.toml`. See [Settings](/docs/app/settings/). ## The map The map takes Vim's keys too. | Keys | Does | |---|---| | h j k l, or the arrows | Move between cards | | Enter | Go into the card | | Backspace | Go up | | gg and G | The first and the last card | | Ctrl+D, Ctrl+U, Ctrl+F, Ctrl+B | Half a page and a page, down and up | | ]] and [[ | The next and the previous card beside this one | | f and F | Jump to a card by its hint, or jump into it | | / and ? | Search forward and back; n and N for the next and previous match | | \* and # | The next and the previous card like this one | | K | What this card is | | + or =, and - | Zoom in and out | | zo, zc, za | Zoom into the card, out to its parent, or back and forth | | zr and zm | More and less detail | | zR and zM | Everything, and the whole map | | zz, zt, zb | Put this card in the middle, at the top or at the bottom | | gf | Open its code | | gr | What uses it | | gd | What it depends on | | gI | Its implementations | | ge | Every card it is joined to | | v and V | Choose cards | | dd | Hide the card, or take a box apart | | cw | Rename | | cc | Rewrite its description | | yy | Yank it as a reference | | p and P | Put what was yanked into the card, or beside it | | o and O | Add a card after or before | | a | Add a card inside | | >> and << | Nest it in the card before, or move it up a level | | gl | Draw a line between cards | | Ctrl+G | Group the chosen cards | | u and Ctrl+R | Undo and redo | | . | Do it again | | m and ' | Mark the card with the next key, and fly back to it | With cards chosen, `d`, `y`, `c`, `>` and `<` act on all of them at once. ## The agents' list | Keys | Does | |---|---| | j and k | Move | | Enter | Press the row: open a group, or the agent's page | | gd | The agent's card on the map | | dd | Stop and archive | | zz | Snooze: archive it for a while, then be reminded | | gp | Pin to the top | | za, zo, zc | Fold or open a group | | zR and zM | Open or fold every group | ## The Vim keys elsewhere If you like Vim's modes but not its window, Settings, Keyboard, **How keys behave** gives the Normal window Vim's typing. The other way round works too. --- # Settings Source: https://graphide.com/docs/app/settings/ > Where Graphide's settings live, the ones most people change, themes, and settings for one project. **Settings**, at the foot of the sidebar or with **Ctrl+,**, has every setting with what it does. A change takes effect at once and is saved to your settings file. ## The settings file Settings are kept in one TOML file, `config.toml`: | System | Where it is | |---|---| | Linux | `~/.config/graphide/config.toml`, or under `$XDG_CONFIG_HOME` | | macOS | `~/Library/Application Support/Graphide/config.toml` | The app's own settings are its `[gred]` table. You can edit the file by hand while Graphide runs. A key Graphide does not know is kept and warned about, and a value it cannot use falls back to its default and is named, so a typo never stops the app. The file holds no secrets: your sign-in is in the system keychain. ```toml [gred] base = "normal" # the window: "normal" or "vim" theme = "ink" # "ink" is Graphide Dark, "marble" Graphide Light reducedmotion = false ``` ## What most people change | Setting | In the file | What it does | |---|---|---| | Editor mode | `base` | The window: **Normal** or **Vim**. See [A tour of the app](/docs/app/#three-windows). | | How keys behave | `editing` | Standard or Vim typing, whichever the window | | Theme | `theme` | **Graphide Dark** or **Graphide Light** | | Density | `density` | How tightly things are spaced; below 1 is tighter | | Zoom | `zoom` | The size of the whole interface | | Reduce motion | `reducedmotion` | Cuts glides, flights and pops | | Buttons and key names | `chrome` | **Full** draws buttons and writes keys in words, such as Ctrl+S. **Minimal** leaves them out and writes keys as Vim does. | | Controls like | | The mouse on the map, in another program's habits | | Show agents on the map | `overlays` | Each agent's mark on the map | | Format on save | `format_on_save` | Off at first | | Open agents as | `agent.open` | An agent's page, or its terminal | | Enter in an agent's box | `agent.enter` | Whether Enter sends and stays, or sends and opens the next agent | | Snooze for | `agent.snooze` | How long Ctrl+M snoozes an agent; half an hour at first | | Sidebar lists | `agent.sidebar` | **To-do** (agents by what they need) or **Projects** | | Notifications | `notify` | Whether the app tells you when an agent needs you | ## Themes **Graphide Dark** (`ink`) is deep blue-green, and **Graphide Light** (`marble`) is pale stone. Choose one in Settings under Appearance, and the whole app fades to it. To follow your system's light and dark, give `theme` both: ```toml [gred] theme = { dark = "ink", light = "marble", follow = "system" } ``` Settings, **Look**, picks a preset that changes the app's whole look beyond its colours. Presets of your own go in a `presets` folder beside the settings file. ## Settings for one project A project's own `.graphide/config.toml` can set a few settings for that project alone: the theme, and Vim options such as `scrolloff`, `number`, `relativenumber`, `ignorecase` and `smartcase`. Settings marks each one a project may set. The same file holds what to [leave out of the map](/docs/first-map/#leave-parts-of-a-project-out). ## Other pages in Settings - **Keyboard** and **Keyboard shortcuts**: how keys behave, and every key. - **Connectors**: sign in to Claude Code and Codex, and connect your clouds and machines. - **Privacy**: what Graphide sends. See [Your code and data](/docs/privacy/). - **Experimental**: features still being built, off until you turn them on. --- # Using gr Source: https://graphide.com/docs/cli/ > What the gr command does, how it finds your project, and the commands you will use most. `gr` is Graphide's command line tool. It installs and updates the app, signs you in, builds and checks maps, answers questions about your code from the map, and connects the coding agents you run in a terminal. Every command talks to the daemon, the one background service Graphide runs for you. ## Help ```sh gr help # every command, by name gr help init # one command in full gr init --help # the same ``` The [command reference](/docs/cli/reference/) is the same help, grouped by task. For `gr claude` and `gr codex` use `gr help claude`: their `--help` goes to Claude Code and Codex. ## Which project A command acts on the project of the folder you run it in, found by climbing to the top of its git repository. Run it from anywhere inside the repository, or name the project with `--root`: ```sh gr status --root ~/code/my-project ``` ## For scripts Most commands take `--json` and print one JSON object instead of words. `gr doctor` exits with 0 when nothing needs attention, 1 when something does, and 2 when something is wrong. ## The commands you will use most | Task | Commands | |---|---| | Set up | [`gr login`](/docs/cli/reference/login/), [`gr app install`](/docs/cli/reference/app/), [`gr app open .`](/docs/cli/reference/app/), [`gr version`](/docs/cli/reference/version/) | | Build the map | [`gr init`](/docs/cli/reference/init/), [`gr map`](/docs/cli/reference/map/), [`gr status`](/docs/cli/reference/status/) | | Ask the map | [`gr query`](/docs/cli/reference/query/), [`gr impact`](/docs/cli/reference/impact/), [`gr code`](/docs/cli/reference/code/), [`gr outline`](/docs/cli/reference/outline/), [`gr summary`](/docs/cli/reference/summary/) | | Run an agent with the map | [`gr claude`](/docs/cli/reference/claude/), [`gr codex`](/docs/cli/reference/codex/), [`gr harness install`](/docs/cli/reference/harness/) | | Work in worktrees | [`gr worktree new`](/docs/cli/reference/worktree/), [`gr worktree land`](/docs/cli/reference/worktree/) | | Fix something | [`gr doctor`](/docs/cli/reference/doctor/), [`gr report`](/docs/cli/reference/report/), [`gr logs`](/docs/cli/reference/logs/) | ## Ask the map from a terminal ```sh gr query "who refreshes the session token" gr impact internal/auth/session.go:Refresh --depth 2 gr code internal/auth/session.go:Refresh gr summary ``` - `gr query` answers a question with a small, ranked slice of the map: the parts that matter and how they join. `--budget` sets how long the answer may be. - `gr impact` lists who calls a symbol, and what a change to it breaks, hop by hop with `file:line`. - `gr code` prints one symbol's source, and `gr outline` a file's symbols. - `gr summary` prints the project's architecture, its busiest parts, entry points and open questions, as Markdown, without calling a model. A symbol is named by its file and name, `path/to/file.go:Name`, or `path:Type.method` for a method. ## Worktrees A worktree is another checkout of the repository on a branch of its own, so agents can work side by side without touching each other's files. `gr worktree` makes worktrees that come with a map: ```sh gr worktree new fix-login # -fix-login, on a new branch, with its map gr worktree ls # every worktree, with its map's state gr worktree land fix-login # merge, push, remove the worktree ``` ## Shell completion ```sh gr completion zsh > "${fpath[1]}/_gr" # zsh gr completion bash > ~/.local/share/bash-completion/completions/gr gr completion fish > ~/.config/fish/completions/gr.fish ``` ## Which servers `gr` talks to Graphide's servers at graphide.com. `gr env` shows which servers this machine's daemon uses, in case someone on your team has pointed it elsewhere. --- # Using plugins Source: https://graphide.com/docs/plugins/ > Install plugins, read what each may do before it runs, approve it, and switch plugins off. Plugins add commands, keys, panels, statusline segments, pickers and badges on the map to Graphide, and tools for your coding agents. A plugin is a folder with a `plugin.toml` and, when it computes anything, a TypeScript script. Some plugins hold only data: themes, icon sets, a Neovim distribution's keys, language grammars or snippets. Those run no code at all. Nothing a plugin adds runs until you approve it, and a plugin can reach only what it asked for and you granted. ## The plugins Graphide ships with | Plugin | Adds | |---|---| | `files` | A file tree panel | | `worktrees` | The repository's worktrees, with their agents and how far each branch is from its base | | `problems` | Language-server problems, in a bottom panel and the statusline | | `outline` | The open file's symbols as a tree | They are written against the same public interface as any plugin, and the ones that only read are approved by the release they came with. ## Install one ```sh gr plugin search markdown # find plugins by what they do gr plugin install store:lunarvim # from Graphide's plugin store gr plugin install https://github.com/someone/their-plugin gr plugin install ./my-plugin # a folder on this computer ``` A source can be: - a name in the store, `store:`, or `store:@`; a bare name with no folder of that name falls back to the store; - a public git repository, or a folder in one, on GitHub, GitLab, Codeberg, Bitbucket, Gitea or Forgejo, or any HTTPS git address. It is pinned to the commit you installed; - a folder on your computer. A project can also name the plugins its people should use; see [Share a plugin](/docs/plugins/share/#for-a-team). ## Approve it An installed plugin waits for your approval. Before you approve, read what it asks for: ```sh gr plugin review lunarvim ``` The review says what the plugin adds, each thing it may do in plain words (such as "reads the files in your workspace" or "sends to and reads from api.github.com"), what those mean together, its files, and its panels drawn as text. It approves nothing. Then approve it, in the app's list of what needs you, or on a terminal: ```sh gr plugin approve lunarvim ``` `gr plugin approve` prints the review again, asks which of the plugin's requests to grant, and whether to approve the version shown. What you approve is that exact version: its content's hash, with the grants you chose. If any file of it changes, it waits for your approval again. Only a person can approve. Graphide refuses an approval that comes from inside a coding agent, so an agent can install a plugin for you but never switch it on. [What a plugin may do](/docs/plugins/permissions/) lists every request a plugin can make. ## Manage your plugins | Command | Does | |---|---| | `gr plugin list` | Every plugin and its state | | `gr plugin status [name]` | How it runs: its handlers' times and its last errors | | `gr plugin config key=value` | Change one of its settings. `key=null` puts the default back | | `gr plugin secret set ` | Enter a token it needs, with nothing shown as you type | | `gr plugin disable ` | Switch it off; nothing is removed | | `gr plugin enable ` | Switch it on again, as it was approved | | `gr plugin update ` | Fetch its newest version; changes wait for approval | | `gr plugin rollback ` | Go back to the version approved before | | `gr plugin remove ` | Remove it. A folder of yours is moved aside, not deleted | A plugin's settings are kept in your `config.toml`, under `[plugins..settings]`. A secret, such as an API token, is kept in your system keychain, never in that file. The plugin's script never sees it: it is sent only to the one host the plugin named for it, or handed to the plugin's own MCP server. ## When a plugin misbehaves Each plugin runs in its own process, so a crash, a slow handler or too much memory stops only that plugin. A plugin that runs past its time limits three times in five minutes, or crashes five times in ten, is switched off for the session. If that happens within an hour of approving a new version, Graphide goes back to the version you approved before it. `gr plugin status ` says why a plugin stopped, and `gr plugin reload ` gives it another go. ## Switch every plugin off ```toml # config.toml plugins_enabled = false ``` Or start Graphide with `GRAPHIDE_PLUGINS=0` for one run. With plugins off, no plugin starts, and `gr plugin` says how to turn them on and does nothing else. The daemon notices the change within a couple of seconds. ## Known limits - On macOS, a plugin's programs (`exec`) and MCP servers do not run yet: the sandbox there cannot keep your workspace read-only. The rest of a plugin runs. --- # Write a plugin Source: https://graphide.com/docs/plugins/write/ > Build a small plugin step by step, with a command, a statusline segment and a panel, then test it and run it in the app. This page builds a plugin called `greeter`. It starts with a command and a statusline segment, then gains a panel that lists the project's Markdown files. You need `gr` and a project open in Graphide; nothing else to install. ## Start from the scaffold ```sh gr plugin new greeter --adds command,status --dir greeter cd greeter ``` `--adds` takes `command`, `panel`, `status`, `picker`, `badges` and `tool`, separated by commas. Without `--dir` the folder goes in the `plugins` folder beside your settings file. You get: | File | What it is | |---|---| | `plugin.toml` | The manifest: the plugin's name, what it adds and what it may do | | `plugin.tsx` | The script | | `plugin.test.ts` | Its tests | | `plugin.d.ts` | The interface's types, for your editor | | `tsconfig.json` | Points TypeScript at `plugin.d.ts` | | `fixtures/files/` | A pretend workspace the tests and previews read | ## The manifest Without its comments, `plugin.toml` says: ```toml name = "greeter" version = "0.1.0" api = "0.1" description = "Greeter: say here what it does and how to use it; agents search this." main = "plugin.tsx" [allow] [[commands]] name = "greeter.hello" title = "Greeter: say hello" description = "Says hello on the message line." [[status]] id = "greeter.status" side = "right" order = 50 ``` `api` is the version of the plugin interface the plugin is written for. The `[[commands]]` table adds a command to the palette, and `[[status]]` a segment to the statusline. Every id starts with the plugin's name and a dot. `[allow]` is empty: this plugin may do nothing beyond drawing what it adds, so it asks for nothing. [plugin.toml](/docs/plugins/manifest/) has every key. ## The script ```tsx import type Plugin from "graphide"; const plugin: Plugin = (on, $) => { on("command", { command: "greeter.hello" }, () => [ { cmd: "message", text: "Hello from greeter" }, ]); on("load", () => { $.status.set("greeter.status", { text: "greeter" }); }); }; export default plugin; ``` The script's default export is called once each time the plugin loads, with two arguments: - **`on`** registers a handler for an [event](/docs/plugins/reference/events/). Here, `command` runs when someone runs `greeter.hello`, and `load` runs when the plugin starts. - **`$`** is everything the plugin can call, its [methods](/docs/plugins/reference/methods/). `$.status.set` fills the segment. A handler asks the app to act by returning [commands](/docs/plugins/reference/commands/): here one `message`, shown on the message line. The script never touches the window itself. ## Test it ```ts import { test } from "graphide/test"; test("hello says hello", async (t) => { await t.command("greeter.hello"); t.expect(t.commands()).toEqual([{ cmd: "message", text: "Hello from greeter" }]); }); ``` Each test runs on a fresh copy of the plugin in a pretend host, with fake time, no network and the files in `fixtures/files/`. Run the checks and the tests together: ```sh gr plugin check . --test ``` ```text ok plugin.test.ts: hello says hello (6 ms) greeter passes (hash 8de468210659) ``` `gr plugin check` reads the manifest and the script and names any problem at its line. [Test and debug](/docs/plugins/test/) has the rest of the test API. ## Run it in the app ```sh gr plugin install . gr plugin approve greeter ``` `gr plugin approve` shows you what you are approving and asks you to confirm, on the terminal. You can approve in the app instead, where the plugin shows in the list of what needs you. Now open the command palette (**Ctrl+Shift+P**), run **Greeter: say hello**, and see the message. The statusline shows **greeter** at the right. ## Add a panel Next, a panel that lists the project's Markdown files and opens one when you choose it. Reading files is something the plugin must ask for, so the manifest gains a request in `[allow]`, a `[[panels]]` table, and an event to hear when files change. Add a default key while you are there: ```toml name = "greeter" version = "0.1.0" api = "0.1" description = "Greeter: says hello, and lists the project's Markdown files in a panel." main = "plugin.tsx" events = ["files.changed"] [allow] fs = ["read:workspace"] [[commands]] name = "greeter.hello" title = "Greeter: say hello" description = "Says hello on the message line." [[status]] id = "greeter.status" side = "right" order = 50 [[panels]] id = "greeter.notes" title = "Notes" icon = "search" dock = "right" [keys.normal] "xh" = "greeter.hello" ``` A default key is bound only where your own keys leave it free. The script reads the files when it loads and again when they change, keeps the list in `$.state`, and draws it when the panel asks for its view: ```tsx import type Plugin from "graphide"; const plugin: Plugin = (on, $) => { on("command", { command: "greeter.hello" }, () => [ { cmd: "message", text: "Hello from greeter" }, ]); async function scan() { $.state.set("notes", await $.fs.files("**/*.md", { limit: 200 })); } on("load", async () => { $.status.set("greeter.status", { text: "greeter" }); await scan(); }); on("files.changed", scan); on("view", { view: "greeter.notes" }, () => { const notes = $.state.get("notes") ?? []; return ( Markdown in this project {notes.map((path) => ( {path} ))} ); }); }; export default plugin; ``` A view is built from [elements](/docs/plugins/reference/elements/), written as JSX: `col`, `text`, `list` and `item` here. The plugin never chooses a colour or a font; the app draws each element in its own look. A view that reads `$.state` is drawn again whenever that state is set, so `scan` needs nothing else to update the panel. `open={{ path }}` on an item opens that file when it is chosen, with no handler. Run the checks again: ```text plugin.toml:6:1: error api.newer: events[0]: the event "files.changed" arrived in api 0.2; this plugin says api = "0.1" (set api = "0.2") ``` `files.changed` is newer than the interface version the scaffold wrote. Set `api = "0.2"` and the checks pass. The reference marks everything that arrived after `0.1` with its version. ## Test the panel Add a test that lays files over the fixtures and reads the panel as text: ```ts test("the panel lists Markdown files only", async (t) => { t.fixtures({ files: { "README.md": "# Hi", "docs/guide.md": "Guide", "main.go": "package main" } }); const v = await t.mount("greeter.notes", { size: [400, 300] }); t.expect(v.text()).toContain("docs/guide.md"); t.expect(v.text()).not.toContain("main.go"); }); ``` ```sh gr plugin check . --test ``` ```text ok plugin.test.ts: hello says hello (13 ms) ok plugin.test.ts: the panel lists Markdown files only (13 ms) the tests used: fs:read:workspace greeter passes (hash f813e0398311) ``` To see a view without the app, draw it as text: ```sh gr plugin render . --view greeter.notes --text ``` ```text Markdown in this project > notes.md ``` ## Work on it live Each change to the files is a new version, and a new version waits for approval. While you work on a plugin, let it load as it stands instead: ```sh gr plugin dev . ``` The plugin loads now and again on every save, without asking each time. Dev mode grants nothing new: a save that asks for more runs without it until you approve, and a save that fails to load leaves the last good version running. It ends with `gr plugin dev --off`, after eight hours, or when the daemon stops. The new `fs` request needs your approval once: run `gr plugin approve greeter` again. The panel's id, `greeter.notes`, is also the command that shows and hides it: find it in the command palette, or bind a key to it. ## Where to go next - [plugin.toml](/docs/plugins/manifest/): every key, and every kind of thing a plugin can add. - [What a plugin may do](/docs/plugins/permissions/): every request a plugin can make and what each allows. - [Test and debug](/docs/plugins/test/): fixtures, the test API, logs and status. - [Share a plugin](/docs/plugins/share/): with a team, through git, or in the store. - [The API reference](/docs/plugins/reference/): every element, event and method. `gr plugin api` prints the same reference on your machine, for the version you have, and the scaffold's `plugin.d.ts` gives your editor the types. --- # plugin.toml Source: https://graphide.com/docs/plugins/manifest/ > The plugin manifest. Its root keys, what a plugin can add, default keys, settings and limits. Every plugin folder holds a `plugin.toml`. It names the plugin, says which version of the interface it is written for, declares what it may do, and lists everything it adds to the app. `gr plugin check` reads it and names any problem at its line. Write the root keys first, before any table. A single bracket, `[allow]`, is a table; a double bracket, `[[commands]]`, adds one more of a kind. Paths name files inside the plugin's folder. ## A complete manifest A small panel that reads the workspace, with a command, a key for it and a setting: ```toml name = "notes" version = "0.1.0" api = "0.3" description = "A panel of workspace notes." main = "plugin.tsx" events = ["files.changed"] [allow] fs = ["read:workspace"] clipboard = "write" [[commands]] name = "notes.copy" title = "Copy the selected note" [[panels]] id = "notes.list" title = "Notes" dock = "right" [panels.keys] y = "notes.copy" [keys.normal] "nn" = "notes.list" [settings.max_notes] kind = "int" default = 100 doc = "The most notes to show." ``` ## Root keys | Key | What it says | |---|---| | `name` | Required. 2 to 40 lowercase letters, digits and hyphens, starting with a letter and ending with a letter or digit. Not a reserved name, and not another installed plugin's. | | `version` | Required. A semantic version, such as `0.1.0`. | | `api` | Required. The interface version the plugin is written for: `0.1`, `0.2` or `0.3`. Using a name that arrived in a later version is an `api.newer` error. A plugin written for an older version keeps working. | | `description` | Required. 1 to 300 characters on what it does and how to use it. Agents search these words. | | `main` | The script, ending in `.ts`, `.tsx`, `.js` or `.jsx`. Leave it out for a plugin that only holds data, or whose panels are static. | | `events` | The background [events](/docs/plugins/reference/events/) the script wants, such as `files.changed`. `load`, `unload` and `settings` need no declaring, and each thing a plugin adds brings its own events with it. | | `eager` | `true` starts the script with the window instead of when it is first needed. Off at first. | | `eager_reason` | Why, when `eager` is on: every window pays the cost of starting it. | ## `[allow]` What the plugin may do. Nothing in it is granted until a person approves it, and nothing outside it is reachable at all: ```toml [allow] fs = ["read:workspace", "write:data"] net = ["api.github.com"] exec = ["rg"] graph = "read" agents = ["read", "write"] ``` [What a plugin may do](/docs/plugins/permissions/) lists every request, what it allows, and the words a person reads before approving it. ## What a plugin can add Each id or name starts with the plugin's name and a dot, such as `notes.list`. Ids are unique across everything one plugin adds. | Table | Adds | |---|---| | `[[commands]]` | A command in the palette, which keys can run. `name` and `title` are required. | | `[[panels]]` | A view docked `left`, `right` (the default) or `bottom`, floating (`float`), or as a tab in the middle (`tab`, since 0.2). `id` and `title` are required; the id is also the command that shows and hides it. `[panels.keys]` gives keys that apply while the panel has the focus. | | `[[status]]` | A segment of the statusline, set with `$.status.set`. | | `[[pickers]]` | A searchable list the plugin fills, opened by its id. `live = true` asks again as the search changes. | | `[[badges]]` | Badges on the map's cards, by node, set with `$.badges.set`. `legend` says what they mean. | | `[documents]` | Lets the plugin follow the files open in the app, for the languages it names. Needed for document events and `$.docs`. | | `[[decorations]]` | Marks inside open code: signs, underlines, tints and words at the end of a line. Needs `[documents]`. | | `[[queries]]` | Marks drawn by a tree-sitter query file, with no script at all. | | `[[layers]]` | A short-lived key mode, entered by one of the plugin's commands. | | `[[menus]]` | A row in one of the app's right-click menus, which runs one of the plugin's commands. | | `[[tools]]` | A tool your coding agents can call through Graphide's MCP server. Needs `agents = ["tools"]`. | | `[[mcp]]` | A whole MCP server for your agents, run in the sandbox. | | `[[agents]]` | A new kind of agent the app can start, spoken to over ACP. | | `[[mentions]]` | A source for `@` in the agent composer. | | `[[languages]]` | A language pack: a WebAssembly grammar, its highlighting queries, and a language server. | | `[[completions]]` | Completions in the code view. | | `[[snippets]]` | Snippets for a language, with tab stops. No script and nothing to approve. | `[[agents]]`, a language's server and terminals run as you, outside the sandbox, and a person's approval says so. `gr plugin api` prints the full rules for each table. A plugin can also carry data: colour themes as `themes/.toml`, icons as SVG or PNG files in `icons/`, and editor presets, such as a Neovim distribution's keys, as `presets/.json`. Its themes join your theme choices once the plugin is approved and on. ## Default keys ```toml [keys.normal] "nn" = "notes.list" [keys.insert] "" = { command = "notes.copy", when = "focus == 'code'" } ``` `[keys.normal]`, `[keys.visual]` and `[keys.insert]` bind keys, in Vim's notation, to the plugin's own commands, panels and pickers. A plugin's keys are defaults: they are bound only where the person's own keys leave the key free. In normal and visual a default cannot be a single unmodified letter, and in insert it must start with a modified key. A `when` clause limits a key to where its [context keys](/docs/plugins/reference/context/) say. ## Settings ```toml [settings.max_notes] kind = "int" default = 100 doc = "The most notes to show." [settings.token] kind = "secret" doc = "Your API token." host = "api.example.com" header = "Authorization" format = "Bearer {}" ``` A setting's key is lowercase letters, digits and underscores. `kind` is `string`, `bool`, `int`, `enum` (with its `values`) or `secret`. Every kind but a secret needs a `default` of that kind. The script reads settings with `$.settings.get`, and a person sets them in their `config.toml` under `[plugins..settings]` or with `gr plugin config`. A secret is entered by the person with `gr plugin secret set` and kept in the system keychain. The script only learns whether it is set. Graphide adds it to requests to the one `host` the setting names, in the `header` it names, written as `format` says. ## Limits ```toml [limits] handler_ms = 1000 memory_mb = 512 ``` A plugin may raise its own time and memory limits, up to a cap: | Key | Default | Cap | For | |---|---|---|---| | `load_ms` | 1000 | 2000 | Loading the script | | `handler_ms` | 500 | 2000 | A command, an act or a pick | | `view_ms` | 250 | 1000 | Drawing a view | | `rows_ms` | 2000 | 5000 | Rows of a long list, and picker entries | | `background_ms` | 500 | 2000 | Events, timers and promises, each slice | | `memory_mb` | 256 | 1024 | The plugin's whole process | The rest are fixed, or a person's own. [Limits](/docs/plugins/reference/limits/) has them all. ## Size A plugin folder holds at most 2 MiB in 200 files; a language pack, 16 MiB in 400. A symbolic link, a hard link to a file outside the folder, or a special file is refused. The script imports only its own files, by a relative path such as `./lib.ts`: `.ts`, `.tsx`, `.js`, `.jsx` and `.json`. There are no packages to install; everything the plugin runs is in its folder. --- # Permissions Source: https://graphide.com/docs/plugins/permissions/ > How a plugin asks for what it needs, what a person approves, every request and what it allows, and what runs outside the sandbox. A plugin may do nothing until a person approves it, and then only what its manifest asked for and the person granted. Each plugin's script runs in a process of its own. It reaches anything outside that process only by asking the daemon, which checks every call against the grant. ## Asking and granting A plugin asks in the `[allow]` table of its [plugin.toml](/docs/plugins/manifest/): ```toml [allow] fs = ["read:workspace"] net = ["api.github.com"] ``` A person approves on their own terminal or in the app: ```sh gr plugin review notes # what you would approve; approves nothing gr plugin approve notes # the same review, then the question ``` The review says, in words, what each request lets the plugin do and what they mean together, lists its files, and shows its panels as text. You choose which requests to grant; a call that needs a request you did not grant fails with `capability.denied`. An approval is for one version: the hash of the folder's contents. When any file changes, by an edit or an update, the plugin waits for approval again. A grant the manifest did not ask for is refused (`approve.capability`). **Only a person approves.** The daemon refuses an approval, a switch to [dev mode](/docs/plugins/test/#work-on-it-live), a raised limit or a rollback that comes from inside a coding agent's process (`approve.from_agent`), and it fails closed when it cannot tell. It stops an agent approving a plugin on its own; it is not a wall against a program on your machine that sets out to get around it. Plugins that ship with Graphide and only read need no approval: the release vouches for them. One that asks for more waits like any other. ## Every request The middle column is what the review says. | In `[allow]` | The review says | What it allows | |---|---|---| | `fs = ["read:workspace"]` | reads the files in your workspace | Reading, listing and finding files inside the project, and the text of the current line and selection. Never Graphide's own folders, `~/.ssh` and other secret folders. | | `fs = ["write:data"]` | keeps files in its own data folder | Writing files in a folder of the plugin's own, and nowhere else. | | `exec = ["rg"]` | runs rg in the sandbox, with your workspace read-only and no network | Running that program with any arguments. Its path is recorded when you approve. | | `net = ["api.github.com"]` | sends to and reads from api.github.com | HTTPS requests to that host. `*.example.com` allows one level of subdomain. | | `net = ["localhost:8080"]` | talks to a program on this machine at port 8080 | HTTP or HTTPS to that port on this machine. | | `graph = "read"` | reads your workspace's graph | Reading the map: nodes, their children and neighbours, and search. | | `graph = ["read", "write"]` | changes this workspace's graph: adds, renames, describes, tags, moves and removes nodes; writes are attributed to the plugin and cannot be undone | Changing the map of the project it runs in. | | `agents = "read"` | sees your agents, what they are doing and what they say | Listing your agents, and reading what each agent and its person said, without tool results or command output. | | `agents = ["read", "write"]` | writes to your agents: messages and text they will read and may act on | Sending an agent a message, or putting text in its composer. | | `agents = ["read", "start"]` | starts agents, which costs money: at most 3 every 10 minutes unless you raise it | Starting agents. | | `agents = ["tools"]` | offers tools your agents may call; what a tool answers is read by the agent | Offering `[[tools]]` to your coding agents through Graphide's MCP server. | | `clipboard = "write"` | puts text on your clipboard | Writing to the clipboard. Never reading it. | | `terminal = true` | opens terminals that run commands as you, outside the sandbox; each one is shown | Opening terminals of its own. | | `docs = "write"` | changes the text of files you have open, each change one undo step | Editing documents open in the app. | | `setup = "read"` | reads how your coding agents are set up on this machine: the names and paths of their instructions, skills, hooks, MCP servers and settings, never a key or a token | Reading your agents' setup. | | `net = ["any"]` | its server may reach any host | The network, for the plugin's own MCP servers that ask for it. The script's own requests still reach only the hosts named. | Requests that arrived after the first interface version need `api = "0.2"` or later in the manifest. [Capabilities](/docs/plugins/reference/capabilities/) in the reference has the methods each one opens. ## The sandbox A program a plugin runs (`exec`) and a plugin's MCP server run in a sandbox: - The workspace is read-only, and so is its git folder. - There is no network, unless an MCP server asked for `net = ["any"]` and you granted it. - The program starts with only `PATH`, `HOME`, `LANG`, `TERM`, `TMPDIR` and the XDG folder names in its environment. Nothing else of yours leaks in. - It stops after 30 seconds or at 1 GiB of memory, and its output is capped at 1 MiB each way. On Linux the sandbox is [bubblewrap](https://github.com/containers/bubblewrap) (`bwrap`). Where there is no sandbox, a plugin's programs do not run at all (`exec.unsandboxed`); they never fall back to running unconfined. macOS's sandbox cannot yet keep a workspace read-only, so on a Mac a plugin's programs and MCP servers are refused this way for now. The rest of a plugin runs. `exec` is also refused when the project is your home folder (`exec.root`). The script's own requests (`net`) go only to the hosts it named, over HTTPS. Plain HTTP, Graphide's own servers, private and cloud metadata addresses are refused, and each redirect is checked again. ## What runs as you Three things a plugin can add run as you, outside the sandbox. The review says so for each, and only approve them for a plugin you trust as you would any program you install: - **Terminals** (`terminal = true`). Each one is shown in the app. - **New kinds of agent** (`[[agents]]`). An agent runs in the workspace with the reach Graphide's own agents have. - **A language's server** (`[languages.server]`), and only in projects you trust. ## Settings and secrets A plugin's settings are yours, in your `config.toml`. A secret setting, such as an API token, is different: you enter it with `gr plugin secret set`, it is kept in your system's keychain, and the plugin never reads it. Graphide adds it to requests going to the one host the setting names, or hands it to the plugin's own MCP server. The plugin learns only whether it is set. ## Limits that stop a plugin A plugin that runs too long, uses too much memory or keeps failing is switched off for the session, and no other plugin notices. Its own time and memory limits can be raised up to a cap by its manifest; others are fixed, or yours to set with `gr plugin config --limit`. See [Limits](/docs/plugins/reference/limits/) and [When a plugin misbehaves](/docs/plugins/#when-a-plugin-misbehaves). ## Errors you may see | Code | Means | |---|---| | `capability.undeclared` | The script called a method whose request is not in `[allow]`. | | `capability.denied` | The request is there, and the person did not grant it. | | `capability.scope` | A call outside what was granted, such as a host not named. | | `fs.refused` | A path outside the project, or in a folder no plugin may read. | | `net.refused` | Plain HTTP, Graphide's own hosts, or a private address. | | `exec.unsandboxed` | No sandbox on this machine, so the program did not run. | | `exec.killed` | The program reached 30 seconds or 1 GiB. | | `approve.stale` | The files changed after the review you approved. Review again. | | `approve.from_agent` | The approval came from inside an agent. | [Error codes](/docs/plugins/reference/errors/) lists every one. --- # Test and debug Source: https://graphide.com/docs/plugins/test/ > Check a plugin, test it on fixtures with fake time, draw its views as text, work on it live, and read its logs and status. A plugin is checked and tested without the app, and without a network. Everything on this page runs on your machine with `gr`. ## Check ```sh gr plugin check . ``` `gr plugin check` reads the folder, the manifest and the script, and names each problem with its file, line and code: ```text plugin.toml:6:1: error api.newer: events[0]: the event "files.changed" arrived in api 0.2; this plugin says api = "0.1" (set api = "0.2") ``` It finds a misspelt key, an id that does not start with the plugin's name, a key bound to a command the plugin does not have, a handler for an event the manifest does not list, a method whose request is missing from `[allow]`, and a script that uses a global plugins do not have (`fetch`, `process`, `require`). `--json` prints the same as data, with the folder's hash and every handler the script registers. [Errors](/docs/plugins/reference/errors/) lists every code. ## Tests A plugin's tests are the `*.test.ts` files beside its `plugin.toml`. Run them with the checks: ```sh gr plugin check . --test ``` ```text ok plugin.test.ts: hello says hello (5 ms) ok plugin.test.ts: the panel lists Markdown files only (5 ms) ok plugin.test.ts: Enter opens the chosen file (6 ms) the tests used: fs:read:workspace greeter passes (hash 6f5b8e0a0cb9) ``` `gr plugin test .` does the same. Each test gets a fresh copy of the plugin in a pretend host: - Time is fake. It starts at 2026-01-01 and moves only when the test says. - There is no network and no program to run. A file, request or program the test's world does not answer for is refused. - The workspace is the world you give it, starting from the folder's `fixtures/`. The last line before the result says which requests the tests used, so you can see a test reach for something you did not expect. ## The world a test runs in `fixtures/files/` is the pretend workspace: every file in it is a file of the project. `fixtures/world.json` holds the rest. A test lays more over both with `t.fixtures`: ```ts t.fixtures({ files: { "README.md": "# Hi", "docs/guide.md": "Guide" }, settings: { max_notes: 10 }, fetch: { "https://api.github.com/repos/o/r": { body: '{"stars": 3}' } }, exec: { "rg": { stdout: "a.go:1:TODO\n" } }, }); ``` `files` adds to `fixtures/files/`; every other key replaces what the folder had. A world can also hold the map's `nodes` and `edges`, your `agents` and what they said, the `state` and `store` the plugin keeps, open `docs`, `worktrees`, git `changes` and what a language server reports. [Test API](/docs/plugins/reference/testing/) has every key and its shape. ## Writing tests `t` drives the plugin as a person and the app would: ```ts import { test } from "graphide/test"; test("Enter opens the chosen file", async (t) => { t.fixtures({ files: { "a.md": "A", "b.md": "B" } }); const v = await t.mount("greeter.notes"); await v.keys("j", ""); t.expect(t.commands()).toEqual([{ cmd: "open.code", path: "b.md" }]); }); ``` | To | Use | |---|---| | Run a command | `await t.command("name", ...args)` | | Show a view | `const v = await t.mount("id", { size: [w, h] })` | | Read a view | `v.text()`, the view as text; `v.tree()`, its elements; `v.selected(key)` | | Press keys in it | `await v.keys("j", "")`, in Vim's notation | | Type in its input | `await v.keys("/")`, then `await v.type("words")` | | Open a picker, choose | `await t.pick("id", "query")`, `await t.choose("id", entry)` | | Send any event | `await t.event("files.changed", { ... })` | | Call a tool as an agent | `await t.tool("name", { ... })` | | Move time on | `await t.advance(ms)` | | Answer a question it asked | `t.asks()`, then `t.answer(value)` | | See what it did | `t.commands()`, `t.messages()`, `t.status(id)`, `t.badges(id)`, `t.state(key)`, `t.logs()` | `t.commands()` is everything the plugin asked the app to do, in order. Opening `b.md` above needed no handler: the item's `open` did it, and the test sees it all the same. `t.expect(value)` takes `toBe`, `toEqual`, `toContain`, `toMatch`, `toHaveLength`, `toBeGreaterThan`, `toBeLessThan`, `toBeTruthy`, `toBeFalsy`, `toBeDefined`, `toBeUndefined` and `toBeNull`, each also after `.not`. ## Draw a view without the app ```sh gr plugin render . --view greeter.notes ``` ```text Markdown in this project > notes.md ``` This is the same text `v.text()` returns and the review shows before anyone approves. `--state world.json` draws it over another world: ```sh echo '{ "files": { "docs/guide.md": "Guide", "CHANGELOG.md": "Changes" } }' > world.json gr plugin render . --view greeter.notes --state world.json ``` ```text Markdown in this project > CHANGELOG.md docs/guide.md notes.md ``` `--png shot.png` also draws a picture, `--size 400x600` sets its size and `--theme ink` or `--theme marble` its colours. ## Work on it live An installed plugin runs the version you approved. Each change to its files is a new version, and waits for approval. While you work on it, run it as it stands: ```sh gr plugin dev . ``` The plugin loads now, and again each time you save. Dev mode grants nothing new: the plugin may do what you approved, and nothing if you never approved it. A save that asks for more runs without it until you approve. A save that does not load leaves the last good version running. Dev mode ends with `gr plugin dev --off`, after eight hours, or when the daemon stops. Only a person can switch it on, on their own terminal. ## When it goes wrong in the app ```sh gr plugin status greeter # its process, its handlers' times, its last errors gr plugin status greeter --logs # with its log lines gr plugin logs greeter --since 2026-10-08T12:00:00Z gr plugin reload greeter # load it afresh, and give it another go ``` `console.log` and the other `console` methods write to the plugin's log, with the file and line, and so does a handler that throws. `gr plugin status` with no name lists every plugin's state. A plugin that keeps failing, runs past its time or memory, or crashes over and over is switched off for the session. Fix it, then `gr plugin reload` gives it another go. When this happens within an hour of approving a new version, the version approved before it comes back by itself; `gr plugin rollback` does the same by hand. --- # Share a plugin Source: https://graphide.com/docs/plugins/share/ > Share a plugin through a git repository, pin it for a team in the repository it serves, or publish it to the plugin store. Plus updates, rollback and importing VS Code and Zed extensions. Whoever installs your plugin approves it on their own machine, whichever way it reaches them. Sharing a plugin never shares an approval. ## Through git Push the plugin's folder to a public repository. Anyone can install it from there: ```sh gr plugin install github.com/you/greeter gr plugin install github.com/you/plugins/greeter # a folder inside the repository gr plugin install github.com/you/greeter@v0.2.0 # a branch, tag or commit gr plugin install https://git.example.com/you/greeter.git ``` A link to the repository or a folder on GitHub, GitLab, Codeberg or Bitbucket works too, as copied from the browser. Graphide fetches public repositories over HTTPS, up to 64 MiB, and reads the files without checking anything out, so nothing in the repository runs while it is fetched. An install records the commit it came from. Without `@`, `gr plugin update` follows the repository's default branch; with one, it stays at what you named. Each update is a new version, and waits for approval. ## For a team To give everyone working in a repository the same plugins, list them in that repository's `.graphide/plugins.toml`, each pinned to the exact contents you reviewed: ```toml [plugins.greeter] source = "github.com/you/greeter@v0.2.0" hash = "6f5b8e0a0cb9d575bfaa41ecdeb715b1ee02bdae239bc104dcf73afe40700f20" ``` `gr plugin hash ` prints a folder's hash, offline. Commit the file. Each teammate then runs, in the repository: ```sh gr plugin install --from-repo ``` Every plugin is fetched from its source and checked against its hash. One whose contents differ is refused. Each person still approves each plugin for themselves, and the plugins run in that repository only. Until then, `gr plugin list --root .` shows them as suggested. Your own list works the same way without hashes: name sources in `[plugins.]` of your `config.toml` and run `gr plugin install --from-config` on a new machine. ## In the plugin store The store lists open-source plugins. Anyone can find and install one by its name: ```sh gr plugin install store:greeter gr plugin install store:greeter@0.2.0 ``` To publish, the plugin's folder needs one of these licences in a `LICENSE`, `LICENCE` or `COPYING` file at its root: MIT, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISC, MPL-2.0, LGPL-2.1-only, LGPL-3.0-only, GPL-2.0-only, GPL-3.0-only, AGPL-3.0-only or Unlicense. You also need to be signed in. ```sh gr plugin publish ./greeter # or a repository link ``` The first time, you choose a public publisher handle, which accepts the Publisher Terms. Then `gr plugin publish` makes a draft, shows you the same review a person sees before approving, and asks you to type `yes` on your terminal. A draft you leave waits; confirm it later with `gr plugin publish --confirm greeter@0.1.0`, or drop it with `gr plugin unpublish greeter@0.1.0`. - A plugin's first version, and any version that asks for something the last listed one did not, waits for review by Graphide's staff. A version that asks for nothing new is listed when you confirm it. - Each version must be higher than every version you confirmed before. - The name is yours once you publish it. - Only a person confirms or withdraws a version, on their own terminal; the daemon refuses one that comes from inside an agent. If a listed version turns out to be unsafe, staff can pull it. Graphide checks the store when the daemon starts and once a day: a version that was pulled is switched off on every machine that has it, and `gr plugin list` and the app's Plugins page say why. You may switch it on again. ## Update and roll back ```sh gr plugin update greeter # fetch the newest version; it waits for approval gr plugin rollback greeter # put back the version you approved before ``` The same daily check finds updates to plugins from the store, and `gr plugin list` names them. ## Bring in a VS Code or Zed extension Themes, icon sets, languages and snippets from an editor extension can become a plugin: ```sh gr plugin import open-vsx:dracula-theme.theme-dracula gr plugin import zed:catppuccin gr plugin import ./some-extension.vsix ``` `open-vsx:` fetches from [Open VSX](https://open-vsx.org), and `zed:` from Zed's registry. A `.vsix`, a Zed extension's `.tar.gz` or an unpacked extension's folder works too. The import keeps only data: no script, native program or other WebAssembly is ever copied, and it lists what did not carry over. The plugin it writes waits for your approval like any other. Imported themes then appear among your theme choices by their names. --- # Your code and data Source: https://graphide.com/docs/privacy/ > What Graphide keeps on your machine and on its servers, the telemetry levels and how to change them, and how to delete things. This page is the practical side: where things are and which switch does what. The [privacy policy](/privacy/) is the full account, and wins where the two differ. ## On Graphide's servers Opening a project in Graphide while signed in puts it in Graphide's cloud. That keeps two things on Graphide's servers: - **A copy of the code.** The files git tracks at the commit you are on, plus changed and new files git does not ignore. A file such as `.env` that is not in your `.gitignore` is copied too. Your git history is not. - **The graph.** Every node, edge and description of the map, and the file paths, symbol names, signatures and short excerpts of code it holds. It keeps uploading while you work. Members of a cloud project can read its copy. To see what is stored: ```sh gr cloud code ``` The telemetry levels below do not change either of these: they are how the cloud half of Graphide works. Signing out stops the graph's uploads. ## Telemetry Graphide sends three kinds of telemetry, at three levels: | Level | Diagnostics and crash reports | The content of your sessions | Screen recordings of the window | |---|---|---|---| | `full`, the default | sent | sent | sent | | `diagnostic` | sent | not sent | not sent | | `off` | not sent, except a usage ping | not sent | not sent | The content of a session is your prompts, the replies, tool calls and their results, and edits. Diagnostics carry file names, symbol names and paths, but no file contents. At `off`, Graphide still sends a usage ping: your install and account ids and which five-minute windows you were active in, never what you did. The first time you run Graphide it tells you this and asks before sending anything. To change the level later: ```sh gr telemetry status gr telemetry diagnostic # or full, or off ``` In the app, it is under **Settings**, **Privacy**: **Usage data and error reports**. For one process, set `GRAPHIDE_TELEMETRY=diagnostic` or `GRAPHIDE_TELEMETRY=off`. `DO_NOT_TRACK=1`, which other developer tools read too, turns telemetry off unless `GRAPHIDE_TELEMETRY` says otherwise. Neither variable can turn anything on. Your logs stay on your machine at every level. `gr logs` shows them, and `gr report` sends them only when you run it. The policy's [telemetry section](/privacy/#telemetry) has the detail, and [how long each thing is kept](/privacy/#retention). ## On your machine A project's map is in `.graphide/` inside the project, and everything else in Graphide's own folders, listed under [Where Graphide keeps things](/docs/install/#where-graphide-keeps-things). `gr telemetry status` prints where your logs are. Your sign-in is kept in the system keychain. ## Deleting things | To delete | Do this | |---|---| | A project's copy on Graphide's servers | `gr cloud delete `, or **Delete cloud copy...** in the project's menu in the app's sidebar. It deletes the code, the graph and its run records for everyone it is shared with, and cannot be undone. Opening the project again while signed in uploads it again. | | A project's Graphide data, here and on the servers | **Remove Graphide data**, in the start page's project menu or in **Settings**. Signed out or offline, only the local data goes, and the app says so. | | Graphide on this machine | [Uninstall](/docs/install/#uninstall) | | Screen recordings, sooner than their 30 days | Email [hello@graphide.com](mailto:hello@graphide.com). | | Your account | Email from the account's address, as the [policy says](/privacy/#controls). | Deleted code leaves Graphide's backups within 7 days. --- # Troubleshooting Source: https://graphide.com/docs/troubleshooting/ > What to run first, the problems people hit most and their fixes, and how to report a bug. ## Start with `gr doctor` ```sh cd ~/code/my-project gr doctor ``` `gr doctor` checks the project end to end and says what is wrong in plain words: the project's folder, its map and whether the map is level with the files, the git hooks, your account, the connection to Graphide's servers and the cloud project, and your agents' setup. Some of what it reports is by design, such as a map that keeps working while the servers are down, and it says which findings apply to you. ```sh gr doctor --fix # run the fixes it can, then check again ``` It exits 0 when nothing needs attention, 1 when something does, and 2 when something is wrong, so a script can use it. ## Signing in **"this machine is not signed in to a Graphide account with active access"**: run `gr login`, then try again. On a machine without a browser, such as one you reach over ssh, `gr login` shows an address and a code to type in a browser anywhere; `gr login --no-browser` asks for that on purpose. **"you are signed in, but this account is pending approval or suspended"**: your account is not active yet. Your [dashboard](/dashboard/) says where it stands. In the app this is the **Waiting for approval** card. ## The app does not open | What you see | What to do | |---|---| | `gr app install` warns there is no Vulkan driver | Install your GPU's Vulkan driver (`mesa-vulkan-drivers` on Ubuntu). Without it the window cannot draw. | | `no_display` | There is no desktop session here, as over ssh. Open Graphide from the desktop. | | `app_running` from an install or update | Quit Graphide first, or use `gr app update`, which waits for the next restart. | | It started misbehaving after an update | `gr app rollback` goes back to the version before. | [Install](/docs/install/#when-the-install-fails) lists every install error. ## Agents or plugins say there is no sandbox On Linux, Graphide's sandbox is `bwrap`: install `bubblewrap` with your package manager. Without it, what Graphide would run in the sandbox, such as a plugin's programs, is refused rather than run unconfined. ## "the Graphide daemon is not answering" The daemon is the background service that serves every project on your machine. It stops when you quit Graphide from the tray or with `gr daemon stop --all`. Start it again: ```sh gr daemon start gr daemon status # what it is doing, and how much it is carrying ``` One daemon serves every window and project for your user. If something reports `bind: address already in use`, another copy is already running; use `gr daemon status` and `gr daemon restart` rather than ending processes by name. ## A command times out after the network dropped On older builds, a command could hang and then fail with a message naming `http://localhost/...` and `timeout awaiting response headers` after the network dropped. The `localhost` there is the daemon, not a website. Update Graphide; until then, `gr daemon stop --all`, then run the command again. ## The map is not building The map's card in the app says what it is waiting for: your place in the queue, the servers being full, another build of the same project, or the internet. [Map your first project](/docs/first-map/) explains each one. From a terminal: ```sh gr status # how far the build is gr doctor # what stands in its way ``` For a very large repository, leave out what you do not need mapped, such as vendored code, generated files or data; see [Leave parts of a project out](/docs/first-map/#leave-parts-of-a-project-out). ## A plugin misbehaves `gr plugin status ` says how it runs and its last errors, and `gr plugin rollback ` puts back the version you approved before. To rule plugins out entirely, start Graphide with `GRAPHIDE_PLUGINS=0`. See [When a plugin misbehaves](/docs/plugins/#when-a-plugin-misbehaves). ## Report a bug In the app, choose **Report bug**: the red button in the status bar, the Help menu, or the command palette (`:report` in the Vim window). Say what happened, and attach the screenshot of the window as it was if you like. From a terminal: ```sh gr report ``` Either way, Graphide collects this machine's recent logs, the daemon's status, your projects' map counts and your settings, with your accounts and email addresses taken out, and sends them. It shows the report's id: quote it in `#feedback` on [our Discord](/discord/). When a report could not be sent, it says where the file is, so you can attach that instead. `gr report --no-upload` keeps the bundle on your machine so you can look at it and attach it yourself, and `gr report --list` shows the reports filed from this machine, by you and by your agents. `gr logs` shows the same events on your own screen. --- # gr command reference From the help of gr 0.2.16. `gr help ` prints a command's help in full. ## gr login Log in to Graphide ``` gr login [flags] ``` - `--browser`: open a browser on this computer even when the session looks remote - `--device`: same as --no-browser - `--from-env`: sign in using GRAPHIDE_LOGIN and GRAPHIDE_LOGIN_TOKEN, or GRAPHIDE_LOGIN_EMAIL and GRAPHIDE_LOGIN_PASSWORD - `--no-browser`: sign in with a code approved in a browser on any computer (default over ssh or without a display) - `--password-stdin`: read the password from standard input ## gr logout Log out of Graphide ``` gr logout [flags] ``` ## gr app The Graphide app: whether a newer one is out, updating it, and going back ``` gr app [command] ``` - `--exe string`: the app's executable (default: the one the daemon last heard from) ### gr app install Install the native Graphide app through your Graphide sign-in ``` gr app install [flags] ``` - `--force`: reinstall even when this commit is already current - `--json`: print one JSON result ### gr app open Open the installed Graphide app on a project folder ``` gr app open [path] [flags] ``` - `--json`: print one JSON result ### gr app rollback Go back to the version before the last update, and move the daemon back with it ``` gr app rollback [flags] ``` ### gr app status Say which Graphide this is, whether a newer one is out, and what is kept ``` gr app status [flags] ``` ### gr app update Download the newest Graphide, check it, and stage it for the next restart Downloads the newest Graphide through your Graphide sign-in, checks it and stages it. It goes in when Graphide restarts from its Update button, or at once with --apply (quit Graphide first). ``` gr app update [flags] ``` - `--apply`: put the staged update in place now instead of at the app's next restart ## gr version Print this build, the daemon's, and whether a newer one exists ``` gr version [flags] ``` ## gr terms Read, and accept, changes to Graphide's terms and privacy policy Show whether Graphide's terms or privacy policy changed since you last accepted them, what changed, and where to read them. `gr terms accept` accepts the version shown, as the app's card does. ``` gr terms [flags] gr terms [command] ``` ### gr terms accept Accept the current terms and privacy policy ``` gr terms accept [flags] ``` ## gr telemetry Show or change what this install reports full diagnostics and the content of your sessions diagnostic diagnostics only: no prompts, completions, tool results or files off only a usage ping: install and account ids and which five-minute windows you were active in, never what you did ``` gr telemetry [status|full|diagnostic|off] [flags] ``` ## gr uninstall Remove Graphide's settings, sign-in and cached data from this computer Remove the machine-local state Graphide keeps for you: settings, saved sign-in, the daemon's state directory and the editor's data folder. ``` gr uninstall [flags] ``` - `--dry-run`: print what would be removed and remove nothing - `-y, --yes`: do not ask for confirmation ## gr completion Generate the autocompletion script for the specified shell Generate the autocompletion script for gr for the specified shell. See each sub-command's help for details on how to use the generated script. ``` gr completion [command] ``` ### gr completion bash Generate the autocompletion script for bash Generate the autocompletion script for the bash shell. ``` gr completion bash ``` - `--no-descriptions`: disable completion descriptions ### gr completion fish Generate the autocompletion script for fish Generate the autocompletion script for the fish shell. ``` gr completion fish [flags] ``` - `--no-descriptions`: disable completion descriptions ### gr completion powershell Generate the autocompletion script for powershell ``` gr completion powershell [flags] ``` - `--no-descriptions`: disable completion descriptions ### gr completion zsh Generate the autocompletion script for zsh Generate the autocompletion script for the zsh shell. ``` gr completion zsh [flags] ``` - `--no-descriptions`: disable completion descriptions ## gr project Start a project on this machine ``` gr project [command] ``` ### gr project new Create a project folder with an empty git repository Create ~/Projects/ (or / with --in), start a git repository in it, and print its path. The same as Start a new project in the editor. It refuses a folder that already exists and a name a folder cannot have; without git installed it still creates the folder and says so. ``` gr project new [flags] ``` - `--in string`: the folder to create it in (default ~/Projects) - `--json`: print the daemon's JSON as it is ## gr init Initialize and build the project graph Builds this project's graph, kept in `.graphide/graph.db`: the structure read from the code, then the descriptions and overview that models write over it. `--extract` and `--slim` stop before any model is called. ``` gr init [flags] gr init [command] ``` - `--arch`: run architecture agents only - `--confirm-large-root`: index a root that does not look like one project (a home directory, a directory of repositories, or one over 20,000 files) - `--extract`: build the deterministic graph only - `--force`: full replace of extractable graph content; also bypasses the non-git-toplevel refusal - `--overview`: run overview agents only - `--park-ahead`: if graph.db was written by a newer gr, move it aside (graph.db.ahead-) and rebuild it with this build - `--slim`: slim init with no agent calls: the deterministic graph, or the free overview partition with --overview - `--specs`: rewrite extracted docstrings into specifications rather than trusting them (one model call per symbol) (default true) - `--yes`: accept the resolved repository root without confirmation ## gr sync Bring the graph back in step with the code Bring the graph back in step with the code after it changes on disk: a pull, a branch switch, an edit. ``` gr sync [flags] ``` - `--agents`: fill the descriptions and modules that are missing (--agents=false for the free structural sync) (default true) - `--dry-run`: report what changed without touching the graph - `--prune`: delete the nodes of files that have left the tree instead of marking them ## gr map Show whether main's map and every worktree's are up to date One line per checkout of this repository: the main checkout first, then each worktree. The stage says where its map stands (current, catching up, behind main, waiting, building, failed), the line under it why, and → the one thing to do about it, and in which checkout. ``` gr map [flags] ``` - `--json`: emit GET /repo/worktrees as JSON ## gr status Report whether the daemon is serving this project ``` gr status [flags] ``` ## gr stop Close this project's workspace in the daemon, if it is open Closes the resolved project's workspace in the machine-wide daemon, releasing its graph.db handle and caches. A no-op if the daemon is not running, or is not holding this project open. ``` gr stop [flags] ``` ## gr worktree Create, list and land git worktrees that have a graph in them A git worktree with a provisioned graph: its own checkout, its own branch, its own .graphide/graph.db, and a workspace on the same the daemon process that already serves the main checkout. ``` gr worktree [command] ``` ### gr worktree land Merge a worktree's branch into the base, then clean up and re-sync Merges a worktree's branch into its base branch, pushes, removes the worktree and its branch, and brings the main checkout's graph up to date before it returns. On a conflict nothing is decided for you: the tree is left as git left it and the command to abort is printed. ``` gr worktree land [flags] ``` - `--base string`: branch to merge into (default: origin's default branch, else master/main) - `--dry-run`: print the sequence and change nothing - `--keep`: merge and push, but leave the worktree and its branch in place - `-m, --message string`: merge commit message (default: git's own) - `--no-push`: merge locally and push nothing ### gr worktree ls List this repository's worktrees, with their graph and daemon state git's worktree list joined with the machine daemon's open workspaces. ``` gr worktree ls [flags] ``` - `--json`: emit the rows as JSON ### gr worktree name Name this worktree's placeholder branch ``` gr worktree name [flags] ``` - `--json`: emit the result as JSON - `--root string`: worktree to name (default: current worktree) ### gr worktree new Create a worktree on a new branch and provision its graph Creates - beside the main checkout, on a new branch , then gives it a graph. ``` gr worktree new [flags] ``` - `--background`: return as soon as the graph build is under way instead of waiting for it - `--base string`: branch the new worktree starts from (origin's tip of it), is compared against and lands into; recorded as branch..base unless it is the default branch (default: the default branch) - `--dir string`: where to put the worktree (default: -, beside the checkout) - `--force`: check out a branch that already exists instead of refusing - `--json`: emit the result as JSON ### gr worktree path Print the absolute path of a worktree, and nothing else For `cd $(gr worktree path foo)` and for scripts. One line, no decoration, nothing on stdout but the path: anything else and the cd lands nowhere. ``` gr worktree path [flags] ``` ### gr worktree rm Close the worktree's workspace and remove its directory Closes the worktree's workspace in the daemon, then removes its directory. Use it rather than `git worktree remove`, which would leave the daemon serving a graph whose files are gone. ``` gr worktree rm [flags] ``` - `--force`: close a live workspace and remove a dirty tree ## gr trust Show or change whether Graphide may run this project's own code Graphide runs a project's own code (its build configuration, for compiler-grade edges) only in a folder you trust: trusted in Graphide's editor (Workspace Trust), or answered yes here. gr asks the first time it needs to, once per project; these change the answer. ``` gr trust [flags] gr trust [command] ``` ### gr trust allow Trust this project to run its own code ``` gr trust allow [flags] ``` ### gr trust deny Do not let Graphide run this project's code, and do not ask again ``` gr trust deny [flags] ``` ### gr trust forget Forget gr's answer for this project, so it asks again ``` gr trust forget [flags] ``` ## gr clear Delete the entire graph for this project Empties the project graph (every node, edge and tag) and the local conversation transcript, and deletes the generated files under .graphide (filter presets, checkpoints, caches). ``` gr clear [flags] ``` - `--yes`: skip the interactive prompt (the daemon's confirmation still applies) ## gr forget Delete this machine's record of what you have been looking at Graphide keeps a local note of the nodes you open, click, edit and spend time on, and uses it to decide what to put in front of you. It lives in .graphide/noderank.db, it never leaves this machine, and this command deletes it. ``` gr forget [node-id] [flags] ``` - `--all`: forget the whole record for this project - `--subtree`: also forget everything under the node - `--yes`: skip the confirmation prompt ## gr summary Print the graph's architecture, hubs, entry points and questions Prints a Markdown architecture report from stored graph facts, with no model calls. --json reads /.graphide/summary.json, which init and sync keep current. ``` gr summary [flags] ``` - `--json`: print the file as written - `--write`: recompute the summary from the graph and write it before printing ## gr query Ask the graph a question (search + typed walk, budgeted) Ask the graph a question; print a budgeted slice of it. ``` gr query [flags] ``` - `--budget int`: answer size in tokens (default 2000) - `--depth int`: hops to walk (default 2, max 3) - `--json`: print the raw result - `--kind string`: only start from nodes of this kind - `--path string`: only start from nodes under this path prefix ## gr impact List callers and users of a node, hop by hop ``` gr impact [flags] ``` - `--budget int`: answer size in tokens (default 2000, max 20000) - `--depth int`: reverse hops to walk (default 3, max 5) - `--include-tests`: include nodes in test files - `--json`: print the raw result ## gr code Print a node's source code Print a node's source, read from its file over its recorded span. ``` gr code [flags] ``` - `--json`: print the raw result ## gr outline List a file's symbols with spans and signatures Print a file's symbols from the graph: name, kind, line span and signature, one per line, with a type's members indented under it. ``` gr outline [flags] ``` - `--json`: print the raw top-level result ## gr similar Find similar code using local embeddings Find similar code by node id, path, or path:symbol. Similarity never proves equivalence or a call. Use --batch for an offline audit: one {ref,k} input and one {ref,hits,model,model_rev} output per line. ``` gr similar [-k N] [--kind K] [--path P] [--json] [flags] ``` - `--batch string`: offline JSONL audit input - `--json`: print the JSON result - `-k, --k int`: maximum similar hits (max 100) (default 10) - `--kind string`: node kind filter - `--path string`: code-path prefix filter ## gr recap Print what a finished turn or build did Print the recap of a finished turn, build or harness batch. ``` gr recap [job-id | recap-id] [flags] ``` - `--json`: print the raw record as JSON ## gr claude Run Claude Code with Graphide injected at launch; writes nothing to your files Start Claude Code in this workspace with Graphide's hooks, permissions and MCP server and its skill passed on its command line (--settings, --mcp-config, --plugin-dir). ``` gr claude [claude arguments...] [flags] ``` ## gr codex Run Codex with Graphide's MCP server injected at launch; writes nothing to your files Start Codex in this workspace with Graphide's graph tools passed on its command line (-c mcp_servers.graphide=...). ``` gr codex [codex arguments...] [flags] ``` ## gr harness Write a terminal agent's integration to disk (or run `gr claude` to write nothing) Write a terminal agent's integration into this workspace, and report what is installed. ``` gr harness [command] ``` ### gr harness install Write a terminal agent's integration into this workspace Write Graphide's integration files for a supported agent. ``` gr harness install [flags] ``` - `--force`: replace Graphide's part of each file even when someone else wrote it last (a teammate, another build, a hand-edit); never touches anything that is not Graphide's ### gr harness list List supported terminal agents and what is installed here ``` gr harness list [flags] ``` ### gr harness status Report a terminal agent's detection and install state Report detection and install state in detail. ``` gr harness status [name] [flags] ``` ### gr harness uninstall Remove a terminal agent's Graphide integration from this workspace Take out what `gr harness install` put in, and only that: our allow entry, our hooks and our legacy deny in .claude/settings.local.json, the graphide skill, and this machine's MCP server registration. Your own rules, hooks and text are left exactly as they were. ``` gr harness uninstall [flags] ``` - `--all`: remove the integration from every workspace this machine has installed into, not just this one; the list comes from Graphide's own ownership ledger ## gr mcp Serve this workspace's graph to an external agent harness over MCP (stdio) Speak the Model Context Protocol on stdin/stdout, exposing the graph tools against the workspace named by --root. ``` gr mcp [flags] ``` - `--allow-any-root`: let switch_root move to any project this machine has registered, not just another worktree of this repository - `--pin-root`: serve only the root this server was spawned on: omits switch_root from the tool surface ## gr agent List, start, read, type into and stop this workspace's agents ``` gr agent [command] ``` ### gr agent bump Send "continue" to the agents an API error stopped (overloaded, a server error, a dropped connection) Find this workspace's Claude Code agents whose last turn an Anthropic API error ended after the CLI's own retries (529 overloaded, a 5xx, a dropped or timed-out connection) and type "continue" into each, as send would. One line per agent: its id, what stopped it, its name, the CLI's words, and whether it was sent. Ids narrow it to those agents. --limited also bumps the agents a usage limit stopped, for once the limit has lifted or the account was swapped. --list only shows them. Exits non-zero when a send was refused. ``` gr agent bump [...] [flags] ``` - `--everywhere`: Every workspace's agents, not only this one's - `--limited`: Also bump the agents a usage limit stopped - `--list`: Show the stopped agents and send nothing - `--message string`: The line to send each one (default "continue") ### gr agent list List agents ``` gr agent list [flags] ``` - `--json`: Print wire objects as JSON ### gr agent new Start an agent with one complete brief ``` gr agent new [flags] ``` - `--codex`: Start Codex instead of Claude Code - `--inbox`: File it into your Inbox once its turn is over and it sits quiet, as a Standard window's agent - `--name string`: Agent label ### gr agent read Read an agent's conversation ``` gr agent read [flags] ``` - `--json`: Print raw transcript data as JSON - `--last int`: Show the last N turns (default 300) ### gr agent send Type one line into an idle Claude Code agent's box and submit it (a message, or a slash command such as /login) Type one line into a Claude Code agent's input box and press Enter, as its person would: a follow-up, or a slash command such as /login or /compact. The words are joined with spaces; - reads the line from stdin. Refused, with nothing typed, unless the agent is running, idle and showing its input box: never while it is in a turn or a question, permission prompt, menu or dialog is open, so it cannot answer one. ``` gr agent send [flags] ``` ### gr agent stop Stop and archive an agent, keeping its conversation (self: the agent running this command, which ends without going to the Inbox) ``` gr agent stop [flags] ``` ## gr cloud Your cloud projects, and building a local graph from one ``` gr cloud [command] ``` ### gr cloud code Show this project's cloud code copy Show the copy of this project's code Graphide keeps on its servers, and this machine's upload of it. Every cloud project has one; deleting the project's cloud copy deletes it. ``` gr cloud code [flags] ``` ### gr cloud delete Delete a cloud project of yours from Graphide's servers (nothing on any computer is touched) Deletes the project's copy on Graphide's servers: its synced graph, the stored copy of its code, its rank scores and its run records. It cannot be undone, and everyone it is shared with loses it too. Nothing on any computer is touched: a clone keeps its code and its local graph, and opening one again while signed in makes a new cloud copy. It also makes room on your account for another project. ``` gr cloud delete [flags] ``` - `--owner string`: whose project, when two share a name: me, or the owner's email - `-y, --yes`: delete without asking ### gr cloud invite Invite a teammate to a cloud project (default: the one this folder is linked to) Adds the Graphide account with this email to the project. The project shows in their `gr cloud projects` (and in `:cloud` in the app) at once, and `gr cloud open` there gives their clone the project's graph, re-linking a clone they already have. They need a Graphide account first: signing in once makes one. ``` gr cloud invite [project] [flags] ``` - `--json`: print the daemon's answer as JSON - `--owner string`: whose project, when two share a name: me, or the owner's email ### gr cloud members List who is in a cloud project (default: the one this folder is linked to) ``` gr cloud members [project] [flags] ``` - `--json`: print the daemon's answer as JSON - `--owner string`: whose project, when two share a name: me, or the owner's email ### gr cloud open Build this machine's graph of a cloud project from its cloud graph Finds this machine's clone of the project (or the folder --root names), checks with git that its code is the project's, and downloads the cloud graph instead of building one: the graph of your commit when the cloud has it, else the nearest older one, updated to your code. When your code is behind the cloud graph it says to pull first (--older takes the older graph it offers instead). With no clone here, --clone clones it first; --cache0 keeps no local graph at all. ``` gr cloud open [flags] ``` - `--cache0`: keep no local graph: agents' graph tools ask the cloud - `--clone`: clone the project first when this machine has no clone - `--dest string`: where --clone clones to (default ~/graphide/) - `--drop-unsent`: re-link a clone even when changes for its old project cannot be sent now (they stay in the set-aside graph) - `--json`: print the daemon's answer as JSON - `--older`: when your code is behind, take the older cloud graph offered - `--owner string`: whose project, when two share a name: me, or the owner's email - `--root string`: the clone to use (default: this machine's clone of the project) - `--url string`: what --clone clones from (default the project's https remote) ### gr cloud projects List the projects on your account and this machine's clone of each Lists every project on your Graphide account, owned or shared with you, with the clone of it this machine has and how that clone's code relates to the project's cloud graph. Open one with `gr cloud open `. ``` gr cloud projects [flags] ``` - `--json`: print the daemon's answer as JSON ### gr cloud remove Take someone out of a cloud project (default: the one this folder is linked to) Removes the member with this email from the project: it leaves their cloud projects, and their graph branches there are deleted. What they landed on main stays. Only the project's owner removes someone else; anyone may remove themself. ``` gr cloud remove [project] [flags] ``` - `--owner string`: whose project, when two share a name: me, or the owner's email ## gr github Connect GitHub and add cloud projects ``` gr github [command] ``` ### gr github add Add a GitHub repository as a cloud project and wait for its map ``` gr github add owner/name [flags] ``` ### gr github connect Get the page for connecting GitHub ``` gr github connect [flags] ``` ### gr github repos List connected GitHub repositories ``` gr github repos [flags] ``` - `--refresh`: refresh repository access from GitHub ## gr org Your orgs, their people, invites and projects ``` gr org [flags] gr org [command] ``` - `--json`: print the daemon's answer as JSON ### gr org accept Accept an org invite ``` gr org accept [flags] ``` ### gr org allow-sharing Allow members to share conversations in this org (owner only) ``` gr org allow-sharing on|off [flags] ``` ### gr org decline Decline an org invite ``` gr org decline [flags] ``` ### gr org invite Invite an existing Graphide account ``` gr org invite [flags] ``` ### gr org invites List invites waiting for you ``` gr org invites [flags] ``` ### gr org leave Leave an org ``` gr org leave [flags] ``` ### gr org list List your orgs ``` gr org list [flags] ``` ### gr org move Move this folder's cloud project into an org ``` gr org move [root] [flags] ``` ### gr org new Make an org ``` gr org new [flags] ``` ### gr org remove Remove a member or withdraw an invite ``` gr org remove [flags] ``` ### gr org roster Show everyone's computers and agents in an org ``` gr org roster [flags] ``` ### gr org share Share my agents' conversations with this org (Claude Code only; Codex is not shared) ``` gr org share on|off [flags] ``` ### gr org show Show an org's people and invites ``` gr org show [flags] ``` ## gr machine Manage the computers on your account ``` gr machine [command] ``` ### gr machine list List the computers on your account ``` gr machine list [flags] ``` ### gr machine revoke Remove a computer from your account ``` gr machine revoke [flags] ``` ## gr plugin Write, check, install and manage Graphide plugins Plugins add commands, keys, panels, status segments, pickers and map badges to the app, written in TypeScript against one interface. ``` gr plugin [command] ``` ### gr plugin api Print the plugin interface: the page, the declaration file, the schema or one topic Topics: elements, events, methods, capabilities, commands, limits, errors, actions, reserved, types, test, context. With no topic, the page an agent reads (api.md); --dts prints plugin.d.ts, --json api.json. ``` gr plugin api [topic] [flags] ``` - `--dts`: print plugin.d.ts - `--json`: print api.json ### gr plugin approve Read what a plugin adds and may do, and approve it (on a terminal only) Prints the review of a plugin: what it adds, each capability it asks for in words, what they mean together, its files, and its panels as text. Then asks, on your terminal, which capabilities to grant and whether to approve the version shown. Nothing of a plugin runs before this. ``` gr plugin approve | builtin [flags] ``` ### gr plugin check Check a plugin folder: its files, its manifest and its script (--test runs its tests) ``` gr plugin check [dir] [flags] ``` - `--json`: print the daemon's JSON as it is - `--test`: run the plugin's own tests too ### gr plugin config Read a plugin's settings, or change them (key=null puts a default back) With no key=value, prints the plugin's settings and their schema. A value is read as JSON when it is JSON (true, 3, "text", null) and as text otherwise; null puts the setting back to its default. A value the setting's kind does not take is refused and said, and nothing else is held back by it. ``` gr plugin config [key=value ...] [flags] ``` - `--disable`: switch the plugin off - `--enable`: switch the plugin on - `--json`: print the daemon's JSON as it is - `--limit stringArray`: set one of your limits for it, key=value (handler_ms=800; null gives it back); on a terminal only ### gr plugin dev Let a plugin's folder load as it stands and again on every save (on a terminal only) Development mode loads a plugin from its folder as it stands, and loads it again each time a file in it is saved, so the plugin can be changed and tried without an approval for every change. ``` gr plugin dev [dir or name] [flags] ``` - `--off`: switch development mode off ### gr plugin disable Switch a plugin off; nothing of it is removed ``` gr plugin disable [flags] ``` - `--json`: print the daemon's JSON as it is ### gr plugin enable Switch a plugin on (an approved one runs as it was approved) ``` gr plugin enable [flags] ``` - `--json`: print the daemon's JSON as it is ### gr plugin hash Print a plugin folder's content hash, offline ``` gr plugin hash [flags] ``` ### gr plugin import Make a plugin of a VS Code or Zed extension's themes, icons, languages and snippets, and install it Make a data plugin of a VS Code or Zed extension, write it to your plugins folder, and install it; it awaits approval like any plugin. ``` gr plugin import [flags] ``` - `--json`: print what was imported, and the install, as JSON - `--out string`: the folder to write the plugin to (default: your plugins folder's ) ### gr plugin install Install a store name, folder or git source, --from-config, or --from-repo; each needs approval Install a store name (store: or store:@), a folder, a repository or folder link on GitHub, GitLab, Codeberg or Bitbucket, or any HTTPS git URL. A bare name falls to the store when no folder matches. A person approves each install. ``` gr plugin install [source] [--from-config | --from-repo] [flags] ``` - `--from-config`: install missing sources named in config.toml - `--from-repo`: install this root's .graphide/plugins.toml with its pinned hashes - `--json`: print the daemon's JSON as it is ### gr plugin list List plugins and their states (--root adds a repository's) ``` gr plugin list [flags] ``` - `--json`: print the daemon's JSON as it is ### gr plugin logs A plugin's log lines ``` gr plugin logs [flags] ``` - `--json`: print the daemon's JSON as it is - `--since string`: only lines after this time, such as 2026-10-08T12:00:00Z ### gr plugin new Start a plugin: a manifest, a script, its declaration file, a test and a fixture ``` gr plugin new [flags] ``` - `--adds string`: what it starts with: command,panel,status,picker,badges,tool (default "command") - `--dir string`: where to write it (default: your plugins folder) - `--json`: print the daemon's JSON as it is ### gr plugin publish Prepare a plugin store draft and ask the person to confirm on their terminal ``` gr plugin publish [folder|link] [--confirm @] [flags] ``` - `--confirm string`: confirm this existing draft on your terminal - `--json`: print the daemon's JSON ### gr plugin reload Load a plugin afresh over its state, and give one that was switched off for failing another go ``` gr plugin reload [flags] ``` - `--json`: print the daemon's JSON as it is ### gr plugin remove Remove a plugin (a folder in your plugins folder is moved aside, not deleted) ``` gr plugin remove [flags] ``` - `--json`: print the daemon's JSON as it is ### gr plugin render Draw one view of a plugin folder on fixtures and print it as text Draws a view of a plugin folder (installed or not) in a confined host, on fixtures, and prints it as text: the same text a plugin's tests read with v.text(), the plugin_render tool returns and the review page shows. ``` gr plugin render [dir] --view [flags] ``` - `--json`: print the daemon's JSON as it is - `--png string`: also write a picture to this file, drawn by the app - `--size string`: x of a picture, such as 400x600 - `--state string`: a JSON file holding the world to draw on, laid over the folder's fixtures (- reads standard input) - `--text`: the text form only (what is printed when no picture is asked for) - `--theme string`: ink or marble - `--view string`: the view to draw: a panel's id, such as todos.list ### gr plugin review Print what a person is shown before approving a plugin; approves nothing ``` gr plugin review [flags] ``` - `--json`: print the daemon's JSON as it is ### gr plugin rollback Restore a plugin's previous approved version ``` gr plugin rollback [flags] ``` - `--json`: print the daemon's JSON as it is ### gr plugin search Find plugins on this machine by words in their name, description and what they add ``` gr plugin search [words] [flags] ``` - `--json`: print the daemon's JSON as it is ### gr plugin secret Enter or clear a plugin's secret: a token it sends only to its host (a terminal only) A plugin's secret setting is a token it needs and never reads: you enter it here, the daemon keeps it in your OS keychain (never config.toml), and puts it in a header of each request the plugin sends to the one host the setting names, or gives it to the plugin's MCP server. The plugin sees only whether it is set. ``` gr plugin secret [command] ``` #### gr plugin secret clear Forget a plugin's secret ``` gr plugin secret clear [flags] ``` - `--json`: print the daemon's JSON as it is #### gr plugin secret set Enter a plugin's secret on this terminal, with nothing shown as you type ``` gr plugin secret set [flags] ``` - `--json`: print the daemon's JSON as it is ### gr plugin status How a plugin runs: its host, its handlers' times, its last errors (no name: every plugin's state) ``` gr plugin status [name] [flags] ``` - `--json`: print the daemon's JSON as it is - `--logs`: include its log lines - `--since string`: with --logs: only lines after this time, such as 2026-10-08T12:00:00Z ### gr plugin test Check a plugin folder and run its own tests (*.test.ts) on fixtures, with fake time and no network ``` gr plugin test [dir] [flags] ``` - `--json`: print the daemon's JSON as it is ### gr plugin unpublish Drop your draft or withdraw a version (a person's terminal for a confirmed version) ``` gr plugin unpublish @ [flags] ``` - `--json`: print the daemon's JSON ### gr plugin update Fetch the newest store version or requested git revision; changes need approval ``` gr plugin update [flags] ``` - `--json`: print the daemon's JSON as it is ## gr doctor Report what is wrong with this project, and fix what can be fixed Check this project end to end and say what is wrong with it in plain words. ``` gr doctor [flags] ``` - `--fix`: run the fixes that can be run from here, then report again - `--json`: print the raw report as JSON ## gr report Bundle logs and status for a bug report Collects this machine's Graphide logs, its daemon status, its graph counts and its config (settings only, with no accounts or emails), scrubs email addresses out of everything else, and uploads the bundle. Pass --no-upload to keep it local and attach it yourself. ``` gr report [flags] gr report [command] ``` - `--agent string`: file as this agent (claude-code, codex, ...) for its user - `--details string`: with --agent: what was called, what came back, what the task was - `--expected string`: with --agent: what was expected instead - `--kind string`: with --agent: bug or improvement (default "bug") - `--list`: list the reports filed on this machine - `--no-upload`: keep the bundle local - `--note string`: one line about what went wrong - `--title string`: with --agent: one line naming the problem - `--tool string`: with --agent: the Graphide tool or feature involved ## gr logs Show this machine's Graphide events ``` gr logs [flags] ``` - `-f, --follow`: keep reading as new events arrive - `--level string`: show only this level and louder ## gr daemon Inspect and control the machine-wide daemon One daemon process serves every Graphide workspace on this machine. ``` gr daemon [command] ``` ### gr daemon jobs List the scheduler's running and queued jobs and its last 50 runs The daemon runs everything through one scheduler: syncs, feed consumers, cloud passes, whole-graph rebuilds. This lists what it is running or holding right now and why each queued job waits, then the last 50 finished runs with their class, workspace, how long they waited and ran, and what they cost. ``` gr daemon jobs [flags] ``` ### gr daemon list List the workspaces the daemon currently holds open ``` gr daemon list [flags] ``` ### gr daemon restart Replace the machine's daemon with a fresh one once what is running finishes ``` gr daemon restart [flags] ``` - `--timeout duration`: how long to wait for the running daemon to exit (default 1m0s) ### gr daemon start Start the machine's daemon, also after Graphide was stopped ``` gr daemon start [flags] ``` ### gr daemon status Report whether the machine's daemon is running ``` gr daemon status [flags] ``` ### gr daemon stop Close a workspace, or stop the whole daemon with --all ``` gr daemon stop [flags] ``` - `--all`: stop the whole daemon, not one workspace - `--end-agents`: with --all, end the agents its terminals run too (by default they keep running and the next daemon adopts them) - `--force`: close the workspace even while work is running - `--root string`: the workspace to close (default: this project) - `--timeout duration`: with --all, how long to wait for the daemon to exit (0: return once it has agreed to stop) (default 1m0s)