Files
paperclip-docs/docs/reference/cli/workspace.md
Aron PrinsandClaude Opus 5 325c9eb819 seo: hand-write titles and descriptions for all 192 pages (#115)
## Why

The build derived `<title>` from the **sidebar label** and the
description from the **first paragraph clipped to 220 characters**. Both
are the wrong source. A sidebar label is written for a 240px-wide nav
that supplies its own context; a search result has none.

On production that produced:

- **7 pages titled "Overview"**, and 32 pages sharing a title with
another page
- **109 of 193 descriptions cut off mid-word**, and 174 over 160
characters (where Google truncates)

```
/guides/welcome/key-concepts/
  BEFORE (220):  ...and if you misunderstand them early, the product wi
```

Near-identical titles are the weak-differentiation signal behind
"crawled — currently not indexed", which is the exact symptom on this
property.

## What changed

`seo_title` and `seo_description` frontmatter on **every one of the 192
pages**, written by hand against each page's real content and optimised
for the click — lead with what the reader can do, name the concrete
things covered, no keyword stuffing, no repeating the title.

| | Before | After |
|---|---|---|
| Duplicate titles | 32 pages | **0** |
| Duplicate descriptions | — | **0** |
| Descriptions cut mid-word | 109 | **0** |
| Descriptions over 160 chars | 174 | **0** |
| Title length (incl. suffix) | up to "Overview" | **26–60** |
| Description length | 31–240 | **122–158** |

**No prose was rewritten.** I measured content overlap between the
colliding pairs first — only 17–23%, so these were always distinct pages
wearing the same label, not duplicate content. The `docs/` diff is **564
insertions, zero deletions**.

### Examples

```
BEFORE — all seven identical:  "Overview | Paperclip Docs"
AFTER:  "Adapters Overview"      "API Overview"        "CLI Overview"
        "Deployment Overview"    "Bundled Skills"      "Optional Skills"
        "Experimental Features"

BEFORE — both identical:  "Issues | Paperclip Docs"
AFTER:  "Issues: Creating and Tracking Work"   /guides/day-to-day/issues/
        "Issues API"                           /reference/api/issues/
```

```
/guides/getting-started/five-minute-path/
BEFORE (220):  The shortest route from a running Paperclip instance to an agent that has
               just completed work for you. After Paperclip is installed, the path takes
               about 5 minutes: create a company, hire a CEO agent, approve its first s
AFTER  (131):  Install Paperclip, create a company, hire a CEO agent, and approve its
               first strategy — a working AI company in about five minutes.
```

## Plumbing

- **`site/build-release.mjs`** prefers the authored fields; the derived
path stays only as a fallback the CI gate prevents ever reaching.
`<title>`, `<meta name="description">`, and the `TechArticle` JSON-LD
all read from the same source.
- **`site/app.js`** uses the same fields, so a client-side transition
cannot leave a different title on screen than the crawler was served.
Verified in-browser: navigating `/guides/day-to-day/issues/` →
`/reference/api/issues/` swaps to exactly the server-rendered values, no
JS errors.
- **`scripts/verify-seo-metadata.mjs`** (new) enforces presence,
uniqueness, length, complete-sentence endings, and the
frontmatter-safety rules. Wired into `docs:test` and CI as its own step.

I negative-tested the gate rather than assuming it works — it correctly
fails on a duplicate title, a mid-word description, and a missing field,
and passes again once restored.

## Automating it going forward

`skills/sync-docs/SKILL.md` now:

- gains an **"Authored SEO metadata"** section: why the fields exist,
the enforced rules as a table, and how to actually write them (title
names the subject not the nav position; description writes for the
click; never generate mechanically from the first paragraph — *that is
the fallback the gate exists to prevent*).
- requires both fields in the **page-authoring instruction** given to
every subagent, with guidance on when to update an existing description
versus leave it.
- runs `docs:test:seo-metadata` and `docs:test:crawlable-links` as
**fail-loud gates in Phase 7** before commit.
- documents all six build gates in the files/gates section.

So once this lands, a new page cannot ship without hand-written
metadata, and a title collision cannot reach production.

## Verified

All six verifiers pass:

```
Static route verification passed
Asset fingerprint verification passed
Hierarchical Skills nav verification passed
Skill source block verification passed (11 skill pages, 1 control page)
Crawlable-link contract passed: 40886 internal links across 194 pages resolve in one hop
Authored-SEO contract passed: 192 pages carry a unique, hand-written seo_title and seo_description
```

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
2026-08-25 22:51:42 +02:00

11 KiB


paperclip_version: v2026.609.0 seo_title: CLI Workspace, Org and Environment Commands seo_description: Inspect a company's structure and execution surface from the terminal: the org chart, agent configuration, and where runs actually happen.

Workspace, Org & Environment Commands

Use these commands when you need to inspect the structure and execution surface of a company from the terminal: the org chart, the agent configurations behind each role, the execution workspaces where runs actually do their work, the environments and leases that back them, and the per-project workspaces. These are the lower-level inspection and control commands you reach for when you are debugging a run, wiring up an environment, or confirming what infrastructure a company is sitting on — not the day-to-day task flow.

All of these commands are read-and-control wrappers over the Paperclip API. They TRIGGER and OBSERVE server-side state; the actual execution (runtime services, runtime commands, environment probes) runs on the Paperclip runtime, not in the CLI.

Note: Every command here accepts the common client flags — --data-dir, --api-base, --api-key, --context, --profile, and --json. See Common Options. Company-scoped subcommands also accept -C, --company-id <id>; ID- and project-scoped subcommands take the id as a positional argument instead.


Org Chart (org)

Use org to pull the company's org chart — either as structured data or as a rendered diagram you can drop into a doc or a status update.

paperclipai org get --company-id <company-id>
paperclipai org svg --company-id <company-id> --out org.svg
paperclipai org png --company-id <company-id> --out org.png
Command What it returns
org get The org chart as structured JSON data.
org svg The org chart rendered as an SVG image.
org png The org chart rendered as a PNG image.

get is company-scoped and respects --json like every other read command. svg and png fetch binary image data:

  • With --out <path>, the bytes are written to that file and the command prints a small { out, bytes } summary.
  • Without --out, the raw image bytes stream to stdout — pipe them to a file yourself (paperclipai org png -C <company-id> > org.png) or into another tool.

Tip: Reach for org svg/org png when you want a shareable snapshot of the reporting structure. Use org get when you are scripting and need the underlying data.


Agent Configurations (agent-config)

agent-config list returns the agent configuration summaries for a company — the resolved adapter/model setup behind each agent, in one place. Use it to audit which configurations are in play before you change an environment or hire.

paperclipai agent-config list --company-id <company-id>

It is company-scoped and read-only. Pair it with --json when you want to diff configurations across companies or feed them into another tool.


Execution Workspaces (workspace)

Execution workspaces are the server-side sandboxes where heartbeat runs do their work. Use the workspace commands to list them, inspect a single one, check whether it is safe to close, review its operation history, update its settings, or drive its runtime.

paperclipai workspace list --company-id <company-id>
paperclipai workspace get <execution-workspace-id>
paperclipai workspace close-readiness <execution-workspace-id>
paperclipai workspace operations <execution-workspace-id>
paperclipai workspace update <execution-workspace-id> --payload-json '{...}'
paperclipai workspace runtime-service <execution-workspace-id> start --payload-json '{...}'
paperclipai workspace runtime-command <execution-workspace-id> run --payload-json '{...}'
Command Arguments Use
list --company-id <id> List all execution workspaces in a company.
get <id> Fetch a single execution workspace.
close-readiness <id> Check whether the workspace is safe to close (no in-flight work that would be lost).
operations <id> List the workspace's operation history.
update <id> --payload-json <json> Patch the workspace with a JSON body.
runtime-service <id> <action> [--payload-json <json>] Control a runtime service in the workspace.
runtime-command <id> <action> [--payload-json <json>] Run a runtime command in the workspace.

For both runtime-service and runtime-command, the <action> positional is one of start, stop, restart, or run. The --payload-json flag carries the runtime target as a JSON body and defaults to {} when omitted.

paperclipai workspace runtime-service <execution-workspace-id> restart --payload-json '{"service":"dev-server"}'
paperclipai workspace runtime-command <execution-workspace-id> run --payload-json '{"command":"npm test"}'

Tip: Run workspace close-readiness <id> before you tear down or close a workspace. It tells you whether closing it now would interrupt active work.

Warning: runtime-service stop/restart act on live runtime processes a run may be depending on. Confirm with workspace get and workspace operations that nothing critical is mid-flight first.


Environments (environment)

Environments describe where and how workspaces run — the backing infrastructure (SSH hosts, containers, capabilities) that runtime services and commands execute against. A lease is a claim on an environment by a workspace. Use these commands to inventory environments, probe their health, create or update them, and inspect the leases against them.

paperclipai environment list --company-id <company-id>
paperclipai environment capabilities --company-id <company-id>
paperclipai environment create --company-id <company-id> --payload-json '{...}'
paperclipai environment get <environment-id>
paperclipai environment leases <environment-id>
paperclipai environment lease <lease-id>
paperclipai environment update <environment-id> --payload-json '{...}'
paperclipai environment delete <environment-id>
paperclipai environment probe <environment-id>
paperclipai environment probe-config --company-id <company-id> --payload-json '{...}'
Command Arguments Use
list --company-id <id> List a company's environments.
capabilities --company-id <id> Report the environment capabilities available to the company.
create --company-id <id> --payload-json <json> Create an environment from a JSON body.
get <environment-id> Fetch a single environment.
leases <environment-id> List the leases held against an environment.
lease <lease-id> Fetch a single environment lease by its own id.
update <environment-id> --payload-json <json> Patch an environment with a JSON body.
delete <environment-id> Delete an environment.
probe <environment-id> Probe an existing environment for reachability/health.
probe-config --company-id <id> --payload-json <json> Probe a candidate config before you create the environment.

Note the two distinct lease commands: environment leases <environment-id> lists every lease on one environment, while environment lease <lease-id> resolves a single lease by its own identifier (it hits /api/environment-leases/{leaseId}). Use leases when you are looking at an environment and want to know who is using it; use lease when you already have a lease id from somewhere else.

# Validate a config before committing it, then create the environment.
paperclipai environment probe-config --company-id <company-id> --payload-json '{"kind":"ssh","host":"build-01.internal"}'
paperclipai environment create --company-id <company-id> --payload-json '{"name":"build-01","kind":"ssh","host":"build-01.internal"}'
paperclipai environment probe <environment-id>

Tip: probe-config is the dry-run path — it checks a candidate configuration without persisting anything. probe validates an environment that already exists. Probe first, create second.


Project Workspaces (project-workspace)

Project workspaces are the workspaces scoped to a single project. They are addressed by a project id (and, for the single-workspace operations, a workspace id) rather than a company id. Use these commands to list, create, update, delete, and drive the workspaces attached to one project.

paperclipai project-workspace list <project-id>
paperclipai project-workspace create <project-id> --payload-json '{...}'
paperclipai project-workspace update <project-id> <workspace-id> --payload-json '{...}'
paperclipai project-workspace delete <project-id> <workspace-id>
paperclipai project-workspace runtime-service <project-id> <workspace-id> restart --payload-json '{...}'
paperclipai project-workspace runtime-command <project-id> <workspace-id> run --payload-json '{...}'
Command Arguments Use
list <project-id> List the workspaces for a project.
create <project-id> --payload-json <json> Create a project workspace.
update <project-id> <workspace-id> --payload-json <json> Update a project workspace. The workspace id is required.
delete <project-id> <workspace-id> Delete a project workspace.
runtime-service <project-id> <workspace-id> <action> [--payload-json <json>] Control a runtime service in a project workspace.
runtime-command <project-id> <workspace-id> <action> [--payload-json <json>] Run a runtime command in a project workspace.

As with execution workspaces, the <action> for runtime-service and runtime-command is one of start, stop, restart, or run, and --payload-json defaults to {}.

paperclipai project-workspace list <project-id>
paperclipai project-workspace delete <project-id> <workspace-id>
paperclipai project-workspace runtime-command <project-id> <workspace-id> run --payload-json '{"command":"pnpm build"}'

Note: update requires the workspace id positional — the command rejects the call if you omit it. create takes only the project id, since the workspace does not exist yet.


See also