How to use Flywheel

Add to a graph you don't own

Add a result under a node you can read, find your fork, and decide who can see your addition.

You can add a child under any node you can read without joining its repository. Your addition goes into your fork: a repository the server creates for you on your first addition to that person's repository, then reuses for later additions to its graphs. The original node stays where it is and becomes your node's boundary parent, a parent in another repository. This is different from a branch, which creates a child node.

When you hold a named Editor or Admin grant on the parent, a node in your fork starts shared like the parent. Its named people can see your addition at the same roles, including members of the parent's repository. That repository's owner gets Admin on the new node, so they can change its sharing later. The parent's Public or Unlisted audience is copied too.

Otherwise your addition starts private unless you have added members to your fork. A Viewer grant, editing through a link, or reading a Public or Unlisted node does not qualify for the copy. Repository members' roles reach every node in their repository. Leave sharing unchanged unless you choose to change it.

If you hold a write role in the parent's repository, the server places your addition there instead. A node in the same repository as all its parents copies their common sharing once: with one parent, the same sharing; with several, the narrowest read visibility (Private, Unlisted or Public) and only the people named on every parent, each at their lowest role. Link write is copied only when every parent grants it. Public plus Unlisted with link write gives Unlisted without link write. The fork copy uses the same intersection when every parent is in the one upstream repository and you hold a named Editor or Admin grant on every parent. The upstream repository owner counts as Admin on every parent; a retained controller counts as Admin on the parent they control. You own the fork and are not copied. Roots and other nodes with boundary parents keep the repository default. Placement, ownership and commit author do not change. Later parent changes do not propagate to existing children, and adding a parent to an existing node leaves its sharing unchanged.

Choose where to work

  • Already inside a local repository? Create and link the node there, then commit locally. The local workflow does not publish anything.
  • Adding directly to a hosted graph? Use the CLI or an MCP agent and let the server choose the repository. Do not clone someone else's repository or ask for membership just to add a node.
  • Want a local copy afterwards? Clone your fork, not their repository.

Web app

Open the parent node to read its content and graph. The canvas's Set as source action followed by a double-click on empty canvas creates a child when you can write the source. The current web branch action can refuse a read-only source with “This shared node is read-only. Branch this node to continue.” If you encounter that refusal, use the CLI or MCP steps below; you do not need repository membership.

After creating the child, open its node URL in the web app to edit it or use Share node to choose its audience. Sharing your addition below explains how to let the original graph's owner see it without sharing an entire repository.

CLI

Read the parent first:

flywheel hosted:node:get "<parent-node-id>" --format=json

can_write: false is expected for someone else's read-only node. Keep its repository_id for the local alternative. owner_email is included only when you own the node, hold a viewer/editor/admin role in its repository, or have it shared with you by name. Public or Unlisted link access alone does not include another account's email, even when you are signed in.

Create your addition without --repository-id:

flywheel hosted:node:create --parent "<parent-node-id>" --title "My result" --format=json

Use --values-file node.json instead of --title for the full node content; see hosted:node:create for the file format. Alternatively, hosted:node:branch creates a child that copies the parent's title:

flywheel hosted:node:branch "<parent-node-id>" --format=json

Both commands return node_id, repository_id, and placement. Report those values from the answer, not by comparing repository IDs:

placementWhere the new node landed
parent_repositoryThe parent's repository, where you hold a write role
forkYour fork of the parent's repository
default_workspaceYour default workspace, for a root created with no parent

The explicit --repository-id forms commit into that named repository; they do not ask the server to choose a fork. Do not use them for this workflow.

Read the new node for its slug_name and actual visibility:

flywheel hosted:node:get "<new-node-id>" --format=json

Report the node, repository, placement and visibility you read back, and read nodes:sharing:get to report who can see it. Change sharing only when asked; do not make the node public merely because its parent is public.

Find shared and public graphs

Unscoped node listings show your own nodes. Request other readable scopes explicitly; --access_scopes accepts a comma-separated list of owned, shared, and public:

flywheel hosted:node:list --access_scopes shared --format=table
flywheel hosted:node:list --access_scopes public --format=table
flywheel graph:get --access_scopes shared --format=json
flywheel graph:get --access_scopes public --filter include:visibility:public --format=json

The node table's owner column is empty for other people's public nodes unless you also have a repository role or the node shared with you by name. Follow node-list pagination and graph next_cursor while has_more is true. A graph read anchored by --node_id "<parent-node-id>" without an access-scope flag already reads every scope you can read. Without a node ID, its default is your own nodes.

Visibility filters narrow the requested scopes; they do not add one. graph:get --filter include:visibility:public alone does not discover other people's public graphs: include --access_scopes public.

MCP agents

Ask your agent to add your result under the node's URL. The bundled skills use this sequence:

  1. Read the parent with flywheel_get_node. can_write: false does not prevent adding a child.
  2. Call flywheel_commit_new_node with the parent's ID in parent_ids, a caller-generated local_temp_node_id, and the full staged_payload. Alternatively, call flywheel_branch_node with the parent's ID and its current revision as expected_revision. Neither request chooses a repository.
  3. Report the answer's node_id, repository_id, and placement: parent_repository means the parent's repository, fork means your fork, and default_workspace means your default workspace. In the flywheel_commit_new_node answer, node_id is inside node while repository_id and placement are top-level fields. Do not infer placement by comparing repository IDs.
  4. Report the new node's visibility from the creation answer (node.visibility for flywheel_commit_new_node). Read it with flywheel_get_node for its slug_name if needed. Leave sharing unchanged.

If a creation response is lost, retry with the same local_temp_node_id, unchanged content and the same MCP session. The saved answer keeps the original repository and placement.

Inside a local repository

Keep the selected local repository as your destination. Read the hosted parent with hosted:node:get to obtain its repository_id. Inspect repo:status first so your commit does not include unrelated staged work. Then create a node here and link it to the parent there:

flywheel repo:node:create --repo "<repository-path>" --title "My result" --format=json
flywheel repo:lineage:add "<parent-node-id>" "<new-node-id>" --parent-repository-id "<parent-repository-id>" --repo "<repository-path>" --format=json
flywheel repo:diff --repo "<repository-path>" --staged --format=json
flywheel repo:commit --repo "<repository-path>" --message "Add result under readable parent" --format=json

The new node stays in your local repository. Its parent stays in the other repository; repo:lineage:list shows the relationship with boundary: true. A local commit publishes nothing, so it has no hosted visibility or server-decided placement to report yet.

Push only when you want to publish. Agents first show the repo:push --dry-run summary and wait for your approval. Publication checks that you can still read the parent; it never redirects the push into another repository.

Work an agent should not publish as it goes can stay in this local repository until it is reviewed and pushed. The server applies initial sharing on push: same-repository parents contribute their common sharing. A node in your fork also copies sharing when every parent is in the one upstream repository and you hold a named Editor or Admin grant on every parent. Other boundary-parent nodes keep their repository's default. The push preserves repository placement, ownership and commit author.

Clone your fork

After your first hosted addition, find your fork:

flywheel hosted:repository:list --format=table

Choose the row with kind: fork, your owner_email, and the parent's repository as upstream_repository_id. Its repository_id is also the one returned by creation. Other kinds are default_workspace for your new roots and other for other repositories, including those owned by someone else.

flywheel repo:clone "<your-fork-repository-id>" "<repository-path>" --format=json

Reading a public node does not grant access to clone its whole repository. You can clone your fork because you own it.

Share your addition

Change sharing only when you choose to. First check who already has access: the Editor/Admin copy already gives the upstream repository owner Admin. To let someone who cannot yet read your addition see it, open the new child, choose Share node, and add their email under Collaborators with the Viewer role. If the parent read includes owner_email, you can use it; otherwise ask that person for their email. Keep the existing people and audience setting. You can instead choose Unlisted for people with the URL or Public for discovery by anyone, if that is what you intend.

An MCP agent must first call flywheel_get_node_sharing, preserve the current sharing_mode unless you asked to change it, and use people.add to add the requested person without replacing anyone else. Omitted collaborators keep the existing people, including the copied Admin grant. Use people.remove or people.set only for a requested removal or exact role, and confirm with another sharing read.

The CLI's nodes:sharing:set follows the same rule: keep the current --sharing_mode and use --people for the requested change. Omitting --collaborators keeps existing people; an explicit list replaces them.

Sharing a node never makes anyone a repository member. It does not let them clone your fork or read your other private nodes. See Repositories for repository-wide membership and access.