| name | psd-atrium |
| description | Use this to work with Atrium, PSD's collaborative content workspace in AI Studio (documents + interactive artifacts, with an internal "intranet" publishing flow). Find and read Atrium documents/artifacts, create new ones, edit them (append or replace), archive them, hard-delete ones you own, and publish/unpublish to a destination. Interactive artifacts fully support real HTML, CSS, and JavaScript — including <script>, <style>, and inline style="…" — pass raw code; the skill base64-encodes it automatically so nothing is stripped or blocked (do NOT work around with legacy attributes like bgcolor/width). Atrium is REAL and live — never say the district has no content workspace. Version-based: reads return the last saved version and edits create a new version; the real-time collaborative editor rail is not reachable from here. |
psd-atrium
Atrium is AI Studio's collaborative content workspace: staff author
documents (markdown) and interactive artifacts (HTML/JS or JSX) together,
organize them into collections, control who can view them, and publish them to
internal destinations (the "intranet" reader) — with a review gate before anything
goes public. This skill lets you (the agent) act on that content through AI
Studio's owner-bound internal broker.
Use it to answer "what's in Atrium about X?", to read a document/artifact, to draft
a new one, to revise one, or to publish one internally.
What this skill can and cannot do
Version-based (what you get here): reads return the last saved version;
writes create a new version, using the same shared services as the MCP/REST
surfaces.
NOT reachable here (session-only, by design — do not claim you can do these):
- The live collaborative editor rail (real-time keystrokes on the purple agent
rail,
comment, and track-changes suggest). Those run only for a logged-in
human in the in-app editor. Your writes land as new versions in the history, not
as live-editor edits.
- A document open in the editor may be ahead of what
read returns until
someone snapshots a version.
- A document's body TEXT is not returned by
read at all — it lives in the
collaborative store. read gives a document's metadata; only small artifact
code comes back inline. You can still replace a document's body with
edit --mode replace (a full new version), you just can't read the old text
back or append to it.
Authentication & identity
The skill calls an owner-bound internal broker. Its signed invocation proof names
the workspace owner; the web tier resolves that active user to an Atrium
Requester and calls the shared content services directly. No reusable content
credential enters the workspace.
You act as the signed workspace owner — reads and writes are visibility-,
ownership-, and capability-gated by that user's authority. Operations are
attributed to that owner, never to a shared service principal.
Subcommands
node /opt/psd-skills/psd-atrium/run.js <subcommand> [flags]
Read
node run.js find --kind document --query "field trip" --status published
node run.js read --id <uuid-or-slug>
find filters: --kind document|artifact, --collection <slug|id>, --tag <t>,
--status draft|published|archived, --query <title text> (case-insensitive).
Create (starts private + draft)
node run.js create-document --title "Sample" --markdown "# Hello" [--collection <slug|id>] [--tags a,b]
node run.js create-artifact --title "Chart" --code "<html><style>…</style><script>…</script></html>" --body-format html
Artifact code fully supports HTML, CSS, and JavaScript — including
<script>, <style>, and inline style="…". Pass raw code; the skill
base64-encodes every write body automatically so it is opaque to AI Studio's
edge firewall (which would otherwise 403 a raw body that looks like markup) and
decoded server-side before it is stored. There is no need to avoid <script>
/ <style> or fall back to legacy attributes like bgcolor/width — real
JS/CSS is the intended way to build an artifact. Artifacts render only inside a
cross-origin sandboxed iframe, never on the app origin.
Optional on both: --visibility private|group|internal|public and
--grants role:staff,building:GHS (group grants). Requesting public needs the
human-held content:publish_public; without it the object is created PRIVATE
and a widen-to-public request is queued for admin approval. Unlike publish, the API
returns no explicit signal for this, so the skill compares requested vs. returned
visibility and adds approvalRequired: true + a visibilityNote when they differ —
relay that the widen is pending approval, not that the object is public.
Edge case the skill can't auto-flag: if you create into a collection whose
default visibility is public and pass no --visibility, the same downgrade
happens server-side, but with nothing to diff against the skill can't add the
note. Always trust the returned visibilityLevel over what you expected.
Edit (creates a new version)
node run.js edit --id <id> --body "new full text"
node run.js edit --id <id> --body "extra paragraph" --mode append
--mode append reads the last saved body and concatenates; it only works when that
body is returned inline (small content). For a large (externally stored) body, use
--mode replace with the full text. Optional: --body-format markdown|html|jsx,
--summary <change note>.
Archive (soft-remove — reversible)
node run.js archive --id <id>
Flips the object's status to archived (via the metadata PATCH; needs the
owner's Atrium authoring authority). Reversible, and the object still
shows up under find --status archived. Archiving also takes any live publication
offline. Prefer archive when you might want the content back; use delete (below)
only when it should be gone for good.
Delete (HARD, permanent)
node run.js delete --id <id>
Permanently removes the object and every version, body, comment, and index
entry. There is no undo — after this, find/read no longer return it and the
reader/editor URLs 404. Needs owner-authorized content deletion.
Two guardrails the server enforces — relay either refusal verbatim:
- Owner-only. You delete as the signed workspace owner, so you can only delete
content that owner owns. Deleting someone else's object returns a
403 error
(the object's existence is masked as 404 if you couldn't view it at all).
- Unpublish first. A published object is refused with a clear
409 message
("unpublish from … first"); delete NEVER auto-unpublishes. Run
unpublish --id <id> --destination <d> for each live destination, then delete.
Use archive for reversible cleanup and delete only for permanent removal of
throwaway/superseded content you own.
Publish / unpublish (honor the approval gate)
node run.js publish --id <id> --destination intranet
node run.js publish --id <id> --destination public_web
node run.js unpublish --id <id> --destination intranet
intranet (and other internal destinations) publish directly with
content:publish_internal. A public destination the key may not publish
directly returns a structured approval_required result (HTTP 202) — this is a
SUCCESS, not an error. Relay its message verbatim so the user knows the
request was queued for a human/admin to approve.
Change who can view it
node run.js set-visibility --id <id> --level internal
node run.js set-visibility --id <id> --level group --grants role:staff,building:GHS
Output contract
- Success (exit 0): stdout is the JSON result (object, list, created ids, new
version id, etc.).
- approval_required (exit 0):
{ "status": "approval_required", "message": "…", "approvalRequired": true } — a public op queued for approval. Relay the message.
- Errors: structured JSON on stdout/stderr with a non-zero exit (see below).
Exit codes
| Code | Meaning | Agent response |
|---|
| 0 | Success (incl. approval_required) | Use the result |
| 1 | Config / usage error | Fix the invocation; do not retry blindly |
| 11 | Unauthorized — signed owner authority is unavailable | Tell the user Atrium access isn't configured; do not retry |
| 12 | Upstream content-API error (403 forbidden / 404 not found / 422 blocked / 5xx) or network | Surface the error verbatim |
| 14 | Rate-limited | Wait a moment, retry once |
Rules
- Atrium exists. Never tell a user the district has no collaborative content
workspace — read/list it live before answering "what's in Atrium?".
- Version-based only. Your reads are the last saved version and your writes are
new versions; you cannot type on the live editor rail or leave live
comments/suggestions.
- You act as the signed workspace owner. Do not imply a shared service
principal owns or authorized the operation.
- Relay approval_required verbatim. A queued public publish is not a failure —
tell the user it is awaiting approval.
- New content is private + draft. Creating does not publish or share it; use
publish (destination) and/or set-visibility as separate, explicit steps.
- Your writes use the signed owner's requester. Keep everything you write
appropriate; it is attributed to, and gated by, that user's permissions.