I wanted to know whether Paperclip does anything a tab full of Claude Code sessions can’t, so I gave it a clean Ubuntu box. The agent orchestrator went past 105,000 GitHub stars in October, and one boring job seemed a fair test of whether the attention is earned. The first thing that broke was not Paperclip. Ubuntu’s own Node.js package is too old for it, and the npm that ships next to it crashed before the installer even finished resolving packages.
These notes cover how to install Paperclip AI the way that worked for me, with Node.js 24, the managed paperclipai CLI and a systemd user service. They also cover reaching the loopback-only dashboard, hiring an agent and handing it a task. I also tried the part the docs don’t cover: running that agent on a local Ollama model through OpenCode with no API key at all. I ran everything in October 2026 on an Ubuntu 26.04 LTS lab VM called box1, with Paperclip 2026.1012.0, OpenCode and Ollama on it, and every command, log line and screen below comes from that box.
Figuring out what Paperclip actually is
Paperclip is a Node.js server with a React dashboard that manages AI coding agents the way a ticket tracker manages people. You create a company, hire agents into an org chart, give them tasks, and Paperclip wakes each agent with a “heartbeat” when it has work, records what it did, and tracks what it cost. It doesn’t ship a model or an agent of its own. The agents are tools you already know, run through adapters: Claude Code, Codex, OpenCode, Gemini CLI, Cursor, Pi, Hermes, Grok Build and Kimi Code, plus plain shell processes and HTTP endpoints. The project is MIT licensed and lives at paperclipai/paperclip on GitHub.
So what does it add over twenty terminal tabs? A queue, an org chart and a memory of every attempt, and that split between orchestration and execution matters more than the marketing suggests. Paperclip decides who works on what and keeps the history, but the actual thinking happens in whichever CLI the adapter launches, with whatever model and credentials that CLI has. The pieces sat on my box like this once everything worked, including the route the UI wanted me to take and could not:

Everything in that picture binds to loopback (127.0.0.1, and ::1 for PostgreSQL), on three ports:
- 3100 for the dashboard and API
- 54329 for the embedded PostgreSQL Paperclip starts itself
- 11434 for Ollama
I did not open a single firewall port for any of it, and with trusted local mode you should not either, because that mode has no login.
Getting Node.js 24 onto Ubuntu
Paperclip needs Node.js 24.11 or newer. Ubuntu 26.04’s archive carries Node 22, which is the version you get from a plain apt install nodejs npm:
apt-cache policy nodejs | head -3
The candidate on a fresh 26.04 install is the 22.x line:
nodejs:
Installed: (none)
Candidate: 22.22.1+dfsg+~cs22.19.15-1ubuntu1
My first attempt installed it anyway, because the docs say npx on Node 22 only prints an unsupported-version warning and carries on. It didn’t get that far. The npm 9.2.0 that Ubuntu packages alongside it died while building the dependency tree, before Paperclip’s own code ever ran.
npm ERR! Cannot read properties of null (reading ‘edgesOut’)
Running npx --yes paperclipai@latest --version with Ubuntu’s nodejs and npm packages produced exactly this:
npm ERR! Cannot read properties of null (reading 'edgesOut')
npm ERR! A complete log of this run can be found in:
npm ERR! /home/philip/.npm/_logs/2026-10-23T09_34_57_785Z-debug-0.log
In the debug log, the stack points at loadPeerSet in the arborist copy under /usr/share/nodejs, so it is the old packaged npm failing on Paperclip’s peer dependencies, not a network or registry problem. Retrying will not fix it. Why NodeSource and not the Snap? Either works, but NodeSource gives you a plain /usr/bin/node that a systemd user service finds without extra PATH work. Purge the distro packages and install Node 24 from NodeSource instead, which publishes a generic nodistro suite that works on 26.04 and 24.04 alike:
sudo apt purge -y nodejs npm
sudo apt autoremove -y
curl -fsSL https://deb.nodesource.com/setup_24.x -o nodesource_setup.sh
sudo bash nodesource_setup.sh
sudo apt install -y nodejs
Check both versions before going further, because the managed install refuses to run on anything older than 24:
node --version
npm --version
On box1 that gave me Node 24 with npm 11:
v24.22.1
11.19.1
If you’d rather use nvm or a different install method, our Node.js on Ubuntu 26.04 guide covers four of them. Anything works as long as node --version reports 24.11 or newer for the user that will run Paperclip.
Installing Paperclip with the managed CLI
The README’s one-liner is npx paperclipai@latest onboard --yes, and it works, but it runs whatever npx has cached each time and there is nothing to update or roll back. For a box that’s going to keep Paperclip around, I used the managed install instead. It puts a paperclipai command in ~/.local/bin and keeps versioned payloads under ~/.paperclip/cli, with no sudo involved:
npx --yes paperclipai@latest install --yes
It took 3 minutes 11 seconds on box1 and ended like this:
Resolving paperclipai@latest from https://registry.npmjs.org...
Installing [email protected]...
Add Paperclip to PATH for this shell:
export PATH="$HOME/.local/bin:$PATH"
Installed paperclipai 2026.1012.0 (latest).
Payload: /home/philip/.paperclip/cli/installs/npm/2026.1012.0
Run paperclipai --version to verify the managed install.
Run in an interactive terminal, the installer offers to add ~/.local/bin to your ~/.bashrc. Over a non-interactive SSH session it only printed the hint above, so add the line yourself and confirm the command resolves:
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
paperclipai --version
The version line also tells you which channel and payload you’re on:
2026.1012.0 (managed npm latest; payload /home/philip/.paperclip/cli/installs/npm/2026.1012.0)
Budget disk for it. The managed store alone measured 1.4 GB on box1 before I had created anything. Most of that is bundled agent runtimes rather than Paperclip itself: in the payload’s node_modules, @openai (the Codex binaries) took 370 MB, @anthropic-ai (the Claude agent SDK) 225 MB, Paperclip’s own packages 426 MB and the embedded PostgreSQL 60 MB. On a 20 GB VM that is fine; on a small cloud instance, check free space before you start.
Running it as a service that survives a reboot
Onboarding writes the instance config, and with --install-service it also registers a systemd user unit instead of holding your terminal. A user unit stops when you log out unless lingering is on for that account, so turn that on first:
sudo loginctl enable-linger $USER
paperclipai onboard --yes --install-service
With --yes and no --bind, you get the Quickstart defaults: trusted local mode, bound to loopback, with the embedded database, local file storage and locally encrypted secrets. The summary it prints is worth reading once, because it lists every file it just created:
│ Using quickstart defaults: local_trusted/private @ loopback (127.0.0.1):3100.
│
│ No environment overrides detected: embedded database, file storage, local encrypted secrets.
│
◆ Created PAPERCLIP_AGENT_JWT_SECRET in /home/philip/.paperclip/instances/default/.env
│
◆ Created PAPERCLIP_TOOL_ACTION_SIGNING_SECRET in /home/philip/.paperclip/instances/default/.env
│
◆ Created local secrets key file at /home/philip/.paperclip/instances/default/secrets/master.key
│
◇ Configuration saved ─────────────────────────────────────────────╮
│ │
│ Database: embedded-postgres │
│ LLM: not configured │
│ Logging: file -> /home/philip/.paperclip/instances/default/logs │
│ Server: local_trusted/private @ loopback (127.0.0.1):3100 │
│ Allowed hosts: (loopback only) │
│ Auth URL mode: auto │
│ Storage: local_disk │
│ Secrets: local_encrypted (strict mode off) │
│ Agent auth: PAPERCLIP_AGENT_JWT_SECRET configured │
│ │
├───────────────────────────────────────────────────────────────────╯
│
◆ Installed and started paperclipai.service.
│
● Paperclip dashboard: http://127.0.0.1:3100
│
└ You're all set!
The last line onboarding printed on box1 was a [telemetry] notice about a dropped batch. Paperclip sends anonymous usage telemetry by default, and the README lists PAPERCLIP_TELEMETRY_DISABLED=1, DO_NOT_TRACK=1 or telemetry.enabled: false in the config as ways to turn it off, which I would do on any box that handles client work. Exporting the variable in your shell does not reach the user service, so put it in ~/.paperclip/instances/default/.env, which the instance already loads, or use the config setting.
Treat master.key and that .env as the crown jewels of the instance. Every secret you later store in Paperclip is encrypted with the key file, so a backup of the database without it is a backup you can’t fully restore. These are the paths the onboarding run created and that I’d copy off the box:
~/.paperclip/instances/default/config.json~/.paperclip/instances/default/.env~/.paperclip/instances/default/secrets/master.key~/.paperclip/instances/default/db(82 MB with one company)
Paperclip reports on itself through the CLI, which is a quicker check than systemctl --user status:
paperclipai service status
Three fields in the output tell you the install is healthy:
active: the unit is runninglinger: it keeps running after you log outhealth.ok: the API answered
On box1 all three came back true:
{
"platform": "systemd",
"serviceName": "paperclipai.service",
"installed": true,
"active": true,
"enabled": true,
"pid": 37476,
"detail": "active",
"linger": true,
"health": {
"ok": true,
"serverVersion": "2026.1012.0"
}
}
Paperclip’s unit file is small. It runs paperclipai run --instance default with Restart=always, and systemctl --user status paperclipai showed the server plus its own PostgreSQL children using 768.7 MB of RAM straight after start. I later hard-stopped the VM from Proxmox to add CPUs, and the service came back on its own at boot with no login, which is the whole point of lingering. The same check, rendered from box1:

One warning shows up in /api/health on a fresh instance, database_backup_missing. It clears once the first automatic backup lands in ~/.paperclip/instances/default/data/backups; you can force one with paperclipai db:backup if you want the warning gone before you trust the box with real work.
Opening the dashboard from another machine
Trusted local mode has no login at all, which is exactly why it binds to 127.0.0.1. On a headless server I didn’t want to change that, so I reached the dashboard through an SSH local port forward from my laptop:
ssh -N -L 3100:127.0.0.1:3100 [email protected]
Then open http://localhost:3100 in the laptop’s browser. If several people need the board, don’t loosen the bind on a trusted-local instance; Paperclip has an authenticated mode for that, chosen with --bind lan or --bind tailnet at onboarding or later with paperclipai configure --section server, and the deployment modes page explains what each one checks. I only ran the loopback mode, so I can’t tell you how the tailnet preset behaves.
A tunnel has one weakness I hit for real. Halfway through the session the route between my workstation and the lab degraded to a few kilobytes per second, and the dashboard, which pulls several megabytes of JavaScript on first load, simply never rendered. The API on the box answered in 2 ms the whole time. If the UI hangs on a blank page behind a tunnel, time a curl of one asset on both ends before you blame Paperclip. I finished the screenshots with a headless Chromium on box1 itself.
Hiring the first agent
The first visit drops you into a four-step wizard. Step one only wants an organization name; Paperclip turns the first letters into the task prefix, so “Box1 Docs Lab” gave me tasks numbered BOX-1, BOX-2 and so on:

Step two names your first agent, and step three is where your choices narrow. The wizard offers a Claude or OpenAI subscription, or a Claude or OpenAI API key behind the “Use API key instead” link, and nothing else:

If you pay for Claude Code or ChatGPT, this is the easy road: install that CLI on the same host, pick the matching card, and the adapter does the rest. The docs mark claude_local and codex_local as the recommended adapters, and the project README on GitHub notes that subscription sign-in also needs Python 3 on the Paperclip host. I had neither key in this lab, so I left the wizard at step three by going back to the dashboard URL and pressing Escape on the overlay. Nothing had been created at that point except the company; the Agents page still said “Create your first agent to get started.” From there, Agents > New Agent lists every adapter:

OpenCode was the adapter I wanted, because it routes to any provider, including a local one. The form had other ideas. For OpenCode it shows an “AI connection” block fixed to OpenRouter, and the setup won’t finish until you paste an OpenRouter API key into this dialog:

With an OpenRouter key that’s a perfectly good path, and the model picker lists 468 OpenRouter models. Without one, the UI is a dead end. The API isn’t, as the next section shows, because the OpenCode adapter itself only needs a provider/model string that the opencode binary on the host can resolve.
Pointing OpenCode at a local Ollama model
Neither the README nor the adapter docs mention Ollama, so this is the part I most wanted to test. The plan was to install OpenCode and Ollama on box1, teach OpenCode about the Ollama endpoint, and create the agent through the CLI so the OpenRouter form never comes into it. If you are new to the OpenCode side, our OpenCode with an OpenAI-compatible API walkthrough explains the provider block used below.
Install the OpenCode CLI globally so the Paperclip service can find opencode on its PATH, then Ollama from its install script:
sudo npm install -g opencode-ai
curl -fsSL https://ollama.com/install.sh -o ollama-install.sh
sh ollama-install.sh
The script warned “No NVIDIA/AMD GPU detected. Ollama will run in CPU-only mode”, which is the honest state of most homelab VMs and the reason for every timing in this section. Our Ollama on Ubuntu 26.04 guide covers the GPU case.
Picking a model that doesn’t think forever
My first model was qwen3:4b. It handles tool calls, which OpenCode depends on, and it fits in a few gigabytes. It also reasons out loud by default, and on CPU that was fatal. OpenCode’s very first request, a 553-token prompt asking for a session title, ran for more than ten minutes while the model produced over 2,900 tokens of thinking at about 5 tokens per second. I killed it and pulled the non-thinking instruct build of the same model instead:
ollama pull qwen3:4b-instruct
OpenCode’s own system prompt is about 6,900 tokens, and Paperclip adds its instructions and skills on top, so Ollama’s context window has to be large enough to hold all of it without truncating. I set 32,768 tokens with a systemd drop-in:
sudo mkdir -p /etc/systemd/system/ollama.service.d
printf '[Service]\nEnvironment="OLLAMA_CONTEXT_LENGTH=32768"\n' | sudo tee /etc/systemd/system/ollama.service.d/context.conf
sudo systemctl daemon-reload
sudo systemctl restart ollama
A window that size costs memory. ollama ps reported the 2.5 GB model at 7.6 GB loaded with the 32k context, which is why box1 went from 8 GB to 16 GB of RAM (and from 4 to 8 vCPUs) partway through.
Telling OpenCode where Ollama is
With the default dangerouslySkipPermissions setting, Paperclip copies your user’s OpenCode config into a temporary directory for every run (with it off, OpenCode reads the global file directly), so either way the provider only has to exist in the normal global config file. Create it:
mkdir -p ~/.config/opencode
vim ~/.config/opencode/opencode.json
This is the exact file the working runs used. The two timeout values are not optional on CPU, and the next part explains why I learned that the hard way:
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"ollama": {
"npm": "@ai-sdk/openai-compatible",
"name": "Ollama on box1",
"options": {
"baseURL": "http://127.0.0.1:11434/v1",
"timeout": 1800000,
"headerTimeout": 1800000
},
"models": {
"qwen3:4b-instruct": {
"name": "Qwen3 4B Instruct (local)"
}
}
}
}
}
Paperclip checks a configured model against opencode models before each run, so make sure the local model shows up there under the ollama/ prefix:
opencode models | grep ollama
One line comes back, and that string is the model id the agent will use:
ollama/qwen3:4b-instruct
Before involving Paperclip, I gave OpenCode the same kind of job on its own to get a baseline: write a one-line hello.txt and reply DONE. It wrote the file and answered correctly, and it took 363 seconds. Prompt processing ran at about 36 tokens per second and generation at 5 to 8, so every fresh 7,000-token prompt costs a few minutes before the model says anything. Keep that number in your head for the next part.
Creating the agent through the CLI
In trusted local mode the paperclipai CLI talks to the API as the board without a token. Look up the company ID the wizard created:
paperclipai company list
Copy the id from the output into a variable, since the next few commands need it:
export COMPANY_ID=dc75778e-b2ac-4f1c-ab36-142183b1ca02
Before the agent exists, decide which account it will act as. Paperclip runs OpenCode as the service user, with OpenCode’s permission prompts switched off for unattended runs (dangerouslySkipPermissions defaults to true for this adapter). On a cloud image whose default user has passwordless sudo, that means the agent can run anything as root, and later in this walkthrough mine did. Use an account without sudo for real work, The other lever is "dangerouslySkipPermissions": false in the adapter config, which hands control back to OpenCode’s own permission rules. I did not test that, and Paperclip defaults it to true precisely so unattended runs do not stall on approval prompts, so a run can hang unless your opencode.json permission rules allow the tools it needs. The non-sudo account is the fix I would reach for first.
The agent also needs a directory to work in. Make it a git repository, since the task below ends in a commit, and give git an identity for the service user:
export WORKDIR="${HOME}/work"
mkdir -p "${WORKDIR}" && cd "${WORKDIR}"
git init -b main
git config user.name "$USER"
git config user.email "$USER@localhost"
echo "# box1 scripts" > README.md && git add . && git commit -m "init"
Then create the agent with a raw adapter config, using that directory as its working directory and a run timeout in seconds. The payload is double-quoted so the shell fills in your own path:
paperclipai agent create -C "${COMPANY_ID}" --json --payload-json "{\"name\":\"CEO\",\"role\":\"ceo\",\"title\":\"Chief Executive Officer\",\"adapterType\":\"opencode_local\",\"adapterConfig\":{\"model\":\"ollama/qwen3:4b-instruct\",\"cwd\":\"${WORKDIR}\",\"timeoutSec\":1800}}"
The response shows what Paperclip adds on its own: five built-in skills that teach the agent how to read and update Paperclip tasks, and a managed AGENTS.md instructions file. Heartbeat timers start disabled, so the agent only wakes when it’s assigned work:
"status": "idle",
"adapterType": "opencode_local",
"adapterConfig": {
"cwd": "/home/philip/work",
"model": "ollama/qwen3:4b-instruct",
"timeoutSec": 1800,
"paperclipSkillSync": {
"desiredSkills": [
"paperclipai/paperclip/paperclip",
"paperclipai/paperclip/paperclip-board",
"paperclipai/paperclip/paperclip-converting-plans-to-tasks",
"paperclipai/paperclip/paperclip-create-agent",
"paperclipai/paperclip/para-memory-files"
]
},
"instructionsEntryFile": "AGENTS.md",
"instructionsBundleMode": "managed"
},
"runtimeConfig": {
"heartbeat": {
"enabled": false,
"maxConcurrentRuns": 20
}
},
Back in the dashboard, the agent page shows OpenCode as the adapter and the local model, and no AI connection was ever asked for:

The Session row stays at “No session” until the first run, and the five Paperclip skills appear under Skills. From here on, the agent behaves like any other in the org chart, whichever model sits behind it. Keep its id from the create response in a variable for later:
export AGENT_ID=922464aa-e74f-4fff-8989-d2c536f96d7e
Yours will differ; paperclipai agent list -C "${COMPANY_ID}" prints it again if you lose it.
Giving the agent a real task
I made the job deliberately boring, because I wanted to watch Paperclip’s plumbing rather than judge the model’s creativity. From the agent page, Assign Task opens a composer that already has the agent and its model selected, plus a Project picker I left empty on this first try. If you are following along, read the project section below first: creating the project and its workspace before the first task should spare you the fallback-workspace failure I hit, although I only tested the fix after the fact. This is the task text I sent, with my own path in it; use yours:
Write a bash script named check-disk.sh in /home/philip/work. It should print the usage percentage of the root filesystem and print WARNING when usage is above 80 percent. Make it executable, run it once, and commit it to git with the message: add check-disk.sh
In the composer it looked like this just before I pressed send:

The agent woke within a second. The task became BOX-1, the agent page grew a “Live Run” card, and the sidebar showed “1 live”. That wake came from the assignment itself, not from a timer, which is how Paperclip behaves by default:

What happened next took about 75 minutes and seven runs, three of which I cancelled myself while changing settings. Most of the problems in it are ones you’d hit with a stronger model too. The runs that mattered, in order:
- First run: two requests died at exactly five minutes, then the agent wrote the script
- Same run: the commit failed in the wrong directory, then the run timed out at 1800 seconds
- Second run, inside a project: the model described its plan and stopped
- Third run, started by Paperclip’s recovery: the same thing, with a bigger prompt
- Fourth run: cancelled when I paused the agent
Ollama 500 after 5m0s on /v1/chat/completions
Paperclip’s first prompt to the model was 8,744 tokens, and at the 30 tokens per second Ollama logged for Paperclip’s prompts, that is close to five minutes of prompt processing before the first byte comes back. OpenCode doesn’t wait that long by default. The Ollama journal showed each attempt ending the same way:
journalctl -u ollama --no-pager | grep chat/completions
Those 500s at exactly 5m0s are the client hanging up, and the cancel task lines confirm Ollama dropped the work:
[GIN] 2026/10/23 - 10:37:12 | 200 | 1m10s | 127.0.0.1 | POST "/v1/chat/completions"
[GIN] 2026/10/23 - 10:40:57 | 500 | 5m0s | 127.0.0.1 | POST "/v1/chat/completions"
srv stop: cancel task, id_task = 11
[GIN] 2026/10/23 - 10:45:59 | 500 | 5m0s | 127.0.0.1 | POST "/v1/chat/completions"
srv stop: cancel task, id_task = 18
Why five minutes on the dot? OpenCode’s provider timeout and headerTimeout both default to 300,000 ms, according to the OpenCode config reference, and on CPU the headers don’t arrive until the whole prompt is processed. That’s why the config file earlier sets both to 30 minutes. The third attempt in that run squeezed through only because llama.cpp had kept most of the prompt in its cache from the cancelled tries. Do not count on that; set the timeouts.
fatal: not a git repository (or any of the parent directories): .git
Once the model got going, it did the first half of the job properly. It wrote this file to /home/philip/work/check-disk.sh with OpenCode’s write tool, then ran chmod +x on it:
#!/bin/bash
usage=$(df / | tail -n 1 | awk '{print $5}' | sed 's/%//')
if [[ $usage -gt 80 ]]; then
echo "WARNING: Root filesystem usage is at $usage%"
fi
echo "Root filesystem usage: $usage%"
The commit is where it went wrong, twice over. This is the tool call from the run transcript, exit code 128:
sudo git config --global user.email "[email protected]" && sudo git config --global user.name "opencode" && sudo git add /home/philip/work/check-disk.sh && sudo git commit -m "add check-disk.sh"
Do not copy that one; it is here so you can recognise it. The tool result the transcript recorded for it was a single line:
fatal: not a git repository (or any of the parent directories): .git
Git’s error came from the working directory. I’d set cwd to /home/philip/work in the adapter config, but the task wasn’t in a project, and the first line of the run log shows Paperclip ignoring my directory in favour of its own scratch space:
[paperclip] No project or prior session workspace was available. Using fallback workspace "/home/philip/.paperclip/instances/default/workspaces/922464aa-e74f-4fff-8989-d2c536f96d7e" for this run.
The sudo worried me more. The Ubuntu cloud image gives its default user passwordless sudo, Paperclip runs the agent as the service user, and OpenCode runs unattended with every permission allowed (Paperclip’s dangerouslySkipPermissions defaults to true for this adapter). So the model reached for root on its own, and the first two git config calls succeeded. Afterwards /root/.gitconfig on box1 held an “opencode” identity. Nothing broke, but the lesson is plain. Run Paperclip under an account that has no sudo rights, because the agent will use whatever that account can do.
After that, the run sat waiting on the model until my timeoutSec of 1800 fired. Paperclip recorded it as timed_out with “Timed out after 1800s” and queued a retry by itself.
Putting the task inside a project with a real workspace
The directory needs a project whose workspace points at the repo. In the dashboard, the Projects > Add Project dialog asks for a name and only offers GitHub repositories as an optional source, so I created the project there with just the name “box1 scripts” and attached the local folder through the CLI. Find the project ID first:
paperclipai project list -C "${COMPANY_ID}"
Mine printed one line with the ID I needed:
id=b69b0092-0246-4e5a-af67-1e55fed87791 name=box1 scripts status=planned urlKey=box1-scripts goalIds=
Then add a local_path workspace for the directory and make it the primary one:
export PROJECT_ID=b69b0092-0246-4e5a-af67-1e55fed87791
paperclipai project-workspace create "${PROJECT_ID}" --json --payload-json "{\"name\":\"work\",\"sourceType\":\"local_path\",\"cwd\":\"${WORKDIR}\",\"isPrimary\":true}"
Move the task into the project. paperclipai issue list -C "${COMPANY_ID}" prints each task’s ID next to its BOX- identifier; BOX-1’s goes into a variable, and the update carries a comment for the agent:
export ISSUE_ID=fea606d2-af53-40be-923c-b67aa896eed3
paperclipai issue update "${ISSUE_ID}" --project-id "${PROJECT_ID}" --status todo --comment "Moved into the box1 scripts project so the run works in ${WORKDIR}. Please commit check-disk.sh there without sudo."
Then raise the agent’s run timeout to an hour, so a slow model isn’t killed mid-thought:
paperclipai agent update "${AGENT_ID}" --json --payload-json "{\"adapterConfig\":{\"model\":\"ollama/qwen3:4b-instruct\",\"cwd\":\"${WORKDIR}\",\"timeoutSec\":3600}}"
How you wake the agent afterwards matters, and it took me three tries. My comment from issue update sat in the task as a queued message, because an automatic retry had already started with the old settings, so I cancelled that run. A plain paperclipai agent wake ceo then started a run with no task attached, and it landed in the fallback workspace again. What worked was a reply typed into the composer on the BOX-1 page: “check-disk.sh is already in /home/philip/work. Run it once, then commit it there with git add and git commit -m "add check-disk.sh". Do not use sudo.” The run it started listed source: issue.comment with the project ID in its snapshot, and /proc/<pid>/cwd of the opencode process pointed at /home/philip/work. If you are setting this up fresh, create the project and workspace first and pick the project in the Assign Task composer, and you skip this whole detour.
Watching Paperclip’s recovery loop
With the directory fixed, the 4B model let me down in a new way. The prompt had grown to 11,187 tokens with the project and comment history (Paperclip later counted 8,544 of them as fresh input and the rest as cached), the first step took about 15 minutes, and the model answered with a plan instead of a tool call: “First, I will check if the file check-disk.sh already exists in /home/philip/work.” OpenCode treats a text-only reply as the end of a turn, so Paperclip marked the run succeeded with 8,544 input tokens, 57 output tokens and a cost of $0.
What came next impressed me. Paperclip noticed that a “succeeded” run had left the task open with nothing scheduled, and woke the agent again on its own. The run’s context named the reason and the limit:
"wakeReason": "issue_disposition_repair",
"wakeSource": "automation",
"retryReason": "issue_disposition_repair",
"retryOfRunId": "51c6a5ab-a078-4f03-a7f0-5b415f7ee139",
In the same snapshot, the recovery block gave the cause as deliberate_wait_without_target with maxAttempts: 2, so a stuck agent gets two nudges, not an endless loop that eats your token budget. The repair run produced another one-sentence plan after 15m40s on a 14,401-token prompt, and the next request was already at 17,496 tokens. On CPU, each lap costs a quarter of an hour, so I pressed Pause on the agent. Paperclip cancelled the in-flight run (“Cancelled due to agent pause”), and its execution recovery settled BOX-1 as Blocked with an “Inspect run” button, instead of leaving it looking busy:

Paperclip’s Audit page keeps every attempt, including the ones I cancelled, with how each was started and how long it ran. That history is the real product here: I could reconstruct the whole 75 minutes from it without touching a log file.

To close the loop, I ran the agent’s script myself (it printed Root filesystem usage: 77%, below the warning threshold) and committed it by hand as ebf44c9 add check-disk.sh. Setting BOX-1 to Done updates the dashboard, which still reads $0.00 month spend, because a local Ollama model reports no cost:

So my verdict on the local route is mixed, and I’d rather say that plainly. Paperclip, OpenCode and Ollama do connect, with no API key and no OpenRouter account, and the agent did write a correct script. A 4B model on eight CPU cores is still far too slow and too passive for Paperclip’s prompts, which grow with every comment and retry. Use this setup to learn the dashboard and test your wiring for free, then put real work on the Claude Code or Codex adapters the wizard offers, or on a GPU-backed model you trust with tool calls. If you go the Claude route, our Claude Code cheat sheet covers the CLI that adapter drives.
What I still don’t know
A few questions stayed open when I shut box1 down, and I’d rather list them than guess:
- Whether a larger local model on a GPU finishes the loop
- Whether the New Agent form will drop the OpenRouter requirement for OpenCode
- How the authenticated
tailnetbind behaves with several users - Whether Paperclip’s sandbox providers would have stopped that
sudo
Of those, the first matters most. The plumbing held up: wake on assignment, workspaces, timeouts, recovery with a hard limit, and an audit trail of every attempt. What failed was a small model that wouldn’t call tools once the prompt passed 11,000 tokens, and I have not tested where that line sits for bigger models. If you try it on a GPU box, our Ollama models cheat sheet is a good place to pick a tool-calling candidate, and I’d start with a project workspace, a non-sudo user and those OpenCode timeouts already set.