The Artifact tool writes a page into the session's own Claude Code
scratchpad by default (<tmp>/claude-<uid>/<project>/<session>/scratchpad),
but pageCopy took the file only from the workspace folder, so such a page
got no copy and Preview said "the file ... is gone" while it was still there.
pageCopy now also accepts that ONE scratchpad, named from the publishing
session's id, its cwd and the workspace account's uid; before reading,
each of its four folders must be a real directory of that account, and each
file is realpath-confined, opened O_NOFOLLOW and must be a regular file of
that uid. Supporting files come only from the page's own root. The older-
page backfill (POST /api/artifacts/:id/copy) uses the session's cwd too.
The noCopy message now says the file may also lie outside both.
Remote clients (docs/plans/remote-clients/README.md, B1–B3 for the Claude pool):
- server/hub/ holds the hub-only code (devices, remote sessions, upload ingest,
LAN gateway), required only in server mode; hub-boundary.test.js keeps local
code from importing it.
- A local install enrolls with `agenthub remote login` or Settings → AI tools →
Company hub; the "Company account" AI Proxy (reserved name agenthub.company)
sends a session through the hub's gateway, which adds a pool account's token —
no credential reaches the machine. Only those sessions are uploaded, hourly
and at their end; secret-shaped strings are redacted on the client.
- Gateway refuses: unknown device (401), a message without a session id, an
unregistered session under AGENTHUB_REMOTE_GATE=block, a user over quota
(EQUOTA), a purged session (410). Device tokens 90 days, conversations 30.
- New alert rule type remote_unmonitored: a company-account session its device
never registered; a late registration clears the flag instead.
- The hub imports a session once per upload round (chunks carry `more`),
not once per chunk.
Artifacts:
- Share an artifact with chosen people (artifact_shares, PATCH sharedWith,
GET /api/artifacts/people) besides everyone; a "Shared with you" tab.
Only the owner or an admin sees or edits who it is shared with; audited.
- Folders: each account's own arrangement (agenthub.artifacts.folders pref).
- A claude.ai page keeps a copy viewable without the publishing account: its
HTML file (and supporting files) snapshotted at publish, or the copy Claude
saves for a Doc / Slides / Design in artifacts-export/ (a synchronous
PostToolUse hint hook, scripts/artifact-export-hint.js, admin switch),
attached to the page at Stop. Viewed in HtmlFrame's sandbox, Markdown, or
pdf.js (pdfjs-dist 6.4.299, legacy build, loaded only for a PDF).
Fixes:
- tmux: a cached /proc/<pid>/exe of an exited server falls back to PATH's
tmux (stop the last pane, start again within 10 s failed with ENOENT).
- shelves: a shelf restores beside changes in other files.
- chat: a finished reply ends the turn even with no hook at all.
- Settings → AI tools: profile list display tweaks.
At a session's Stop every untracked .html was snapshotted as a report, so a
web project not yet committed had its index.html taken into its owner's
Artifacts. An index.html, a page under a site folder (www, public, dist,
build, src, static, templates, assets, site, _site) or one beside scripts or
stylesheets (outside the workspace root) is now a site's own page and left
alone; a standalone HTML report is still captured.
A row said nothing about when its content last changed, and the install list
could not tell who still runs an old version. `artifacts.version_at` (new
column, existing rows from `updated_at`) is stamped only when a snapshot is
replaced — a rename or share toggle leaves it — and served as `versionAt`:
skill and file rows read "Updated 3h ago", the detail sheet "Last updated".
`GET /api/artifacts/:id/installs` gives each skill install a `state` —
latest / outdated / removed / unknown — from its Claude skill copies' hash
against the newest snapshot, shown as a badge.
A shared skill followed its owner's ~/.claude/skills folder only, so one
uploaded from a browser (or living in a plugin) stayed at its first snapshot
for good. Share again (a skill's ⋯ menu and detail sheet) now takes the
owner's copy on the server — its source folder, else the same-named skill of
a plugin they installed at user scope — and shares it; with no copy it asks
for the folder and uploads it onto that row (`id`). An upload whose skill is
named like one the uploader already has replaces that row's version instead
of adding a twin. Installers are then offered Update, as before.
- Skill snapshot/upload: a key file's name (.env, *.pem, id_rsa, .netrc,
.credentials.json…) is always refused, but a word like token/secret/
password/credential only in a data file's name — design-tokens.md or
count_tokens.py is skill content, not a key.
- System Health: off Linux the History, CPU threads and Busiest processes
cards (all read from /proc) are left out instead of shown empty; the CPU
bar without a sample and Windows' always-zero Load row go too.
- Users pick their own pool account per tool (/api/me/pool-accounts,
Settings → AI tools), within their groups, refused while pinned.
- Admin user detail, 9router update, session replay and Antigravity
catalog changes from parallel sessions.
A skill in the Hub was a snapshot taken once: the owner changing
~/.claude/skills/<name> changed nothing there, and an installer had to
uninstall and install again to get a newer version.
- syncSkillSources (on GET /api/artifacts, at most every 15 s): a skill row
taken from a folder — the owner's ~/.claude/skills/<name>, or the
workspace's .claude/skills/<name> — is brought up to it. Only a folder
whose names/sizes/mtimes changed is read again, with a pick's checks (no
symlink, no secret, <= 5 MB, a member's files as theirs); a change is a
NEW snapshot, the old one dropped, and an artifact_changed broadcast.
- artifacts.version (snapshot content hash) and source_hash (the folder's
when last taken, additive columns): an upload or a Hub edit records the
folder as it is then, so only a LATER folder change replaces it.
- A list row's updateAvailable: installed, and the viewer's copy differs
from version. The page shows Update (a pack: Update N); install with
{update: true} replaces the copies (old ones moved aside) and is not
counted as another install.
- A Claude Docs `batch` that creates a doc is captured like an `Artifact`
publish, titled by the doc's name and linked by its own frame URL.
- At Stop/SessionEnd, each pptx/docx/xlsx/pdf/html a workspace session
created or changed is snapshotted into its owner's library (`auto`);
an unchanged file is skipped, a changed one refreshes its snapshot.
- Server mode: a page with no owner carries a suggested owner (the
workspace or home its session ran in). The suggested user claims or
declines it; an admin claims or assigns any. New tab Unowned /
Is this yours? on the Artifacts page; all three actions audited.
- omp-share.js: an admin's switch (S3) runs omp's own auth broker + gateway as
the host on loopback; a member's omp pane reaches it as a scoped client keyed
by its pane token (clients file = live omp panes only), runs on
--model agenthub/<model>, never holds a credential.
- omp catalog: --allow-home, so a workspace at the account's home keeps its
sessions there (they were recorded under a temp dir and dropped).
- Settings → Appearance → Open Markdown as: Preview (default) or Raw, for
Files/Changes, the config viewer and a chat's file panel.
- First-login password change and password rules, avatar URLs, Artifacts
"Mine" includes installed shared skills/plugins, a member's own hook pages.
- Artifacts page laid out like an app store: hero search, category chips,
shelves by kind, app-icon cards with one primary pill and a detail sheet
- POST /api/artifacts/:id/uninstall: a skill's copies in ~/.claude/skills and
~/.agents/skills are moved to ~/.claude/agenthub-replaced-skills/
(-uninstalled-<time>), never deleted; a plugin runs
`claude plugin uninstall --scope user --keep-data` as the caller;
ENOTINSTALLED when nothing is there; allowed while installs are off
- Uninstall on the card, the ⋯ menu and the detail sheet, after a confirm
- Chat: an Agent step shows its task, status and tool calls and opens its conversation in place; Windows paths (E:\…, C:/…) in replies open as files
- Prompt: attach a file on this computer by path (native picker), clearer too-large messages
- Artifacts: edit title/description and a skill's files (new snapshot), Reinstall, install history, Hub-only rows, skills installed into ~/.claude/skills and ~/.agents/skills
- Files: batch upload of small files in one extract
- AI Tools: npm install falls back to --prefix ~/.local when the global prefix is not writable
- Settings → Git → Your git identity: SSH keys are one tab per host kind
(GitHub · GitLab, AWS CodeCommit, More keys, Other hosts); opens on the
AWS tab when only an RSA key exists.
- Artifacts: a file type the sandboxed preview cannot show (Office, zip,
PDF) offers Download only, never a blank Preview.
- Artifacts search: `%`/`_`/`\` in a query match literally (LIKE ... ESCAPE).
- Skill frontmatter rewrite replaces a key with its continuation lines and
quotes values YAML could misread.
- Plugin marketplace.json is read with a 1 MB streaming cap.
- Artifact lists look each owner up once.
- Artifacts hub: upload a file from the computer; make a skill by uploading a
Markdown file, files, a folder or a .zip/.skill, or by writing it in the
dialog; add plugins by picking from the list a marketplace link answers
(POST /api/artifacts/plugin/inspect); Settings → AI tools → Artifacts Hub.
- Console tabs are combos of up to four split panes (ConsoleTabs, PaneGrid).
- Accounts: an own avatar (PUT/DELETE /api/me/avatar, raster only, ≤ 1 MB,
<data dir>/avatars/), shown with name and role at the sidebar's foot and on
the workspace owner groups (GET /api/users/:id/avatar, owner_avatar_at).
- Users page: per-user storage (GET /api/users/storage, measured in a worker)
and account-pool spend/tokens per account (server/lib/pool-usage.js).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Artifacts (/artifacts): claude.ai pages sessions publish (captured from the
Artifact tool's hook), pinned workspace files, skills and plugins, each
kept as a snapshot; shared ones appear in a Hub and a skill or plugin
installs into the viewer's own account (server/lib/artifacts.js,
/api/artifacts, docs/plans/artifacts/).
- Workspace extra folders: clone one or more related repos beside the
workspace and add them in one step (POST /api/lanes/:id/sources/clone).
- A pane that ended by itself while tmux kept running is no longer offered
for resume (tmux.serverStartedAt in reconcileOrphans).
- Changes panel: a folder that is not a git repo opens on Files, and its
files open from there.
- Plus the parallel sessions' work in this tree: File Explorer button in the
panel header, user delete, RSA SSH keys, chat/terminal and pet fixes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>