About temp-files
A skill for temporarily passing files, directories, and site snapshots between agents during collaboration. It stores items by path, supports short links, and uses expiring storage with separate user and agent scopes.
Key features
- 01Upload and overwrite files or directories
- 02List relay contents
- 03Download files or directory ZIPs
- 04Delete files and directories
- 05Create and revoke short links
- 06Automatically extract downloaded archives
Use cases
- 01Hand a skill file to another agent for testing
- 02Transfer a staging-site snapshot to a collaborator
- 03Let a recipient retrieve files through a short link
- 04Remove temporary files after a handoff
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ starchild-ai-agent/ official-skills --skill temp-filesAfter installing, type/temp-filesin Claude Code to confirm it loaded.
Bundled filesscripts/tf.py
Details
From the project READMETemp-Files — Workroom file relay
This skill lets one agent drop temporary files, directories, or whole-site snapshots to another agent without polluting the long-term backup namespace and without an external file host.
| Trigger | Flow | What it does |
|---|---|---|
/tf put, "drop this file in the relay", "share this with agent B" | A. Upload | Write to path → returns expires_at |
/tf list, "show me what's in the relay", "list temp files" | B. List | One-level ls: files + subdirs |
/tf get, "pull X down", "download X" | C. Download | File straight through / dir as zip |
/tf rm, "delete X from the relay" | D. Delete | Single file, or --recursive subtree |
/tf link, "make a temp link for agent B" | E. Short link | Mint a tf_xxxx internal short link |
Every command hits the same service (sc-agent-backup.internal) and
authenticates with the container's built-in CONTAINER_JWT. Identity and
path are derived from the JWT:
user_id = JWT.userInfoID, agent_scope = JWT.containerId (defaults to
default). You cannot reach, see, or delete relay files belonging to another
user or another agent.
Difference vs. the backup skill (must read)
| Dimension | backup skill | temp-files skill (this one) |
|---|---|---|
| Purpose | Long-term agent state | Short-term handoff, collaboration relay |
| Addressing | Server-generated backup_id | Caller-supplied path |
| Model | Immutable tar.gz bundle | Path-based filesystem, overwritable |
| Quota | 5 bundles / user, hard cap | Byte quota + per-file size limit |
| TTL | None | Default 7 days, sliding on access/overwrite, hard cap 60 days |
| Cross-agent | Restore the whole bundle | Per-file / per-directory + short link |
Never mix the two. "Restore an entire agent state" → use backup.
"Hand off one artifact so the other agent can carry on" → use this skill.
Operational rules
Rule 1 — Do not use the relay as a file host
Default file TTL is 7 days. Even with overwrite/download sliding renewal,
the hard cap is 60 days. Anything that needs to stick around goes through
backup or volume-backup.
Rule 2 — Path whitelist
The server only accepts segments matching [A-Za-z0-9._\- ]. It rejects
.., absolute paths, empty segments, and control characters. Just pass a
relative path:
skills/my-skill/SKILL.md✅sites/staging/index.html✅../escape.txt❌ → 400 bad_path/abs/oops.mdgets its leading slash stripped — better not to send it
Rule 3 — Short links are "agent-to-agent inside", not public sharing
The first-pass short link follows a capability URL model:
- Whoever holds
tf_xxxxxxxxcan fetch it (the code itself is the credential — 64 bits of entropy) - But still requires the 6PN internal network + a valid
CONTAINER_JWT(for audit) - A browser or bare
curlhas no token, so it gets 401 — that's expected, not a bug - Cross-user agents can fetch, because that is exactly the Workroom handoff use case
Correct flow:
- Agent A calls
/tf putto upload - Agent A calls
/tf linkand receivestf_xxxxxxxx - Agent A sends the short link to agent B over Workroom
- Agent B (inside Fly, with its own
CONTAINER_JWT, possibly under a different user) callstf fetch tf_xxxxxxxxto retrieve it
Do not hand http://sc-agent-backup.internal:8080/t/<code> to an end user
to open in a browser — it isn't publicly reachable. If/when public sharing
ships, wait for the phase-B public resolver.
Cleanup rule: once the receiver confirms they have the file, the sender
should immediately tf unlink <code> to revoke the short link and stop the
token from lingering. Sensitive content must be unlinked — don't rely on
TTL as a backstop.
Rule 4 — Stop on failure, do not silently retry
If any tf.py subcommand exits non-zero, stop immediately and return the
stderr verbatim to the user. Do not "let me try again for you."
Install path
The skill installs into /data/workspace/skills/temp-files/. Every command
runs from the agent's working directory:
python3 skills/temp-files/scripts/tf.py <subcommand> ...
Command reference
Environment for every command:
CONTAINER_JWT— injected by ai-agent, requiredTEMP_STORAGE_URL— optional, defaults tohttp://sc-agent-backup.internal:8080
Global output switches (place before the subcommand):
--verbose: emit full payload / error meta (for debugging)--json: stable JSON envelope, same keys on success and failure- success:
{ok: true, error: "", message: "ok", detail: "", data: {...}}datadefaults to the command's compact view (minimum useful field set)- with
--verbose,databecomes the server's raw payload (all fields)
- failure:
{ok: false, error: "<code>", message: "...", detail: "...", exit_code: N}erroris the server's error code (e.g.bad_path/not_found/quota_exceeded) orusage_error/http_error- with
--verbose, includes ametasub-structure (HTTP status / server's original message+detail)
- success:
- default (no switches): compact output, the smallest useful set of fields (readable by humans and agents alike)
Note: tf list and tf links without --json print a human-friendly table;
with --json they go through the envelope and data carries the full
entries/links array.
Recommended defaults (quick reference)
| Flag | Recommended | Why |
|---|---|---|
link --ttl-seconds | 3600 (1 hour) | Long enough for the receiver to fetch once, short enough not to linger |
put --ttl-days | 7 (default) | Covers a typical review cycle |
fetch --extract | always pass it | Auto-unpack, one less step, zip-slip defence built in |
get on a directory | must pass --zip | Server has no plain-directory download mode |
unlink after handoff | call as soon as the receiver confirms | Short code = credential; sensitive content must be revoked |
A. Upload / overwrite
python3 skills/temp-files/scripts/tf.py put <local-file> <remote-path> \
[--ttl-days N]
Example:
python3 skills/temp-files/scripts/tf.py put ./SKILL.md skills/demo/SKILL.md
# → {"path": "...", "size_bytes": ..., "expires_at": ...}
Same-name uploads overwrite; the response returns a fresh expires_at.
B. List
python3 skills/temp-files/scripts/tf.py list [--prefix PATH]
No --prefix lists the root; --prefix sites/ lists one level under that.
C. Download
# Single file
python3 skills/temp-files/scripts/tf.py get <remote-path> <local-dest>
# Whole directory as a zip
python3 skills/temp-files/scripts/tf.py get <remote-dir> <local-dest.zip> --zip
A successful download slides the TTL forward by 7 days.
D. Delete
# Single file / empty directory
python3 skills/temp-files/scripts/tf.py rm <remote-path>
# Non-empty directory
python3 skills/temp-files/scripts/tf.py rm <remote-dir> --recursive
E. Short links
python3 skills/temp-files/scripts/tf.py link <remote-path> \
[--zip] [--ttl-seconds 3600]
# → {"code": "tf_xxxxxxxx", "url": "http://.../t/tf_xxxxxxxx", ...}
# List currently active short links
python3 skills/temp-files/scripts/tf.py links
# Revoke
python3 skills/temp-files/scripts/tf.py unlink <code>
Short link TTL defaults to 1 hour and caps at 7 days (independent of the file's own TTL).
F. Pull data via a short link (what the receiving agent runs)
# Download + auto-unpack (strongly recommended)
python3 skills/temp-files/scripts/tf.py fetch <code> <local-dest> --extract
# Or specify the extract directory
python3 skills/temp-files/scripts/tf.py fetch <code> ./pack.zip --extract ./out
# Without --extract: download only, no unpack
python3 skills/temp-files/scripts/tf.py fetch <code> <local-dest>
Any caller with a valid CONTAINER_JWT can fetch (cross-user is fine).
Zip auto-detect: when the server returns Content-Type: application/zip,
fetch and get automatically rename the local file to end in .zip and
tell you in the JSON output via "kind": "zip".
Auto-unpack (--extract):
- Uses Python's built-in
zipfile/tarfile; no dependency on systemunzip/7z - Supported formats:
.zip/.tar/.tar.gz/.tar.bz2/.tar.xz(detected by magic bytes, not the file suffix) - Built-in zip-slip / tar-slip defence:
..segments are rejected; symlink members are rejected - With no value: extracts to a sibling directory (archive name minus suffix); with a value: extracts into the specified directory
- After a successful extract, the JSON output includes
extracted_kind/extracted_to/extracted_top
Example JSON output (with --extract):
{
"saved": "output/tf_from_4814.zip",
"kind": "zip",
"bytes": 7363,
"sha256": "...",
"content_type": "application/zip",
"server_filename": "temp-files-share.zip",
"extracted_kind": "zip",
"extracted_to": "output/tf_from_4814",
"extracted_top": ["temp-files-share/"]
}
So the receiving agent should:
- Call
fetchwith--extractby default - Read
extracted_tofrom the stdout JSON — files live in that directory - If the JSON contains
extract_skippedorextract_error, fall back to thesavedpath and handle it manually based onkind
Typical scenarios
Scenario 1: agent A hands a skill to agent B for testing
# A:
python3 skills/temp-files/scripts/tf.py put ./my-skill.zip skills/my-skill.zip
python3 skills/temp-files/scripts/tf.py link skills/my-skill.zip --ttl-seconds 3600
# Receive tf_xxxxxxxx, post it to B in Workroom
# B: (recommended: fetch + auto-unpack in one shot)
python3 skills/temp-files/scripts/tf.py fetch tf_xxxxxxxx ./inbox.zip --extract
# The fetch JSON already includes sha256 — no need to rerun sha256sum
# cd into JSON.extracted_to to test; write a report
python3 skills/temp-files/scripts/tf.py put ./test-report.md reports/test-report.md
python3 skills/temp-files/scripts/tf.py link reports/test-report.md --ttl-seconds 1800
# Send the report short link back to A
# Once A has the report:
python3 skills/temp-files/scripts/tf.py unlink tf_xxxxxxxx # revoke the original skill short link
Scenario 2: agent A hands a staging site to agent B
# A:
cd ./staging-site/
python3 skills/temp-files/scripts/tf.py put-dir . sites/foo --ttl-days 14
python3 skills/temp-files/scripts/tf.py link sites/foo --zip
# B receives a directory-zip link
# B:
python3 skills/temp-files/scripts/tf.py fetch tf_xxxxxxxx ./foo.zip --extract
cd ./foo
# Edit, then push back
python3 skills/temp-files/scripts/tf.py put-dir . sites/foo
Security boundary cheatsheet
- 6PN only: the service returns 403 on the public internet
- JWT must be valid and
type ∈ {container, access} - Each user has an isolated namespace; each agent under that user has its own sub-scope
- Direct path access at
/temp-files/...is user-isolated (you cannot reach others') - Short links at
/t/<code>are capabilities: anyone with the code can fetch (still requires 6PN + any valid JWT for audit) - Paths reject
..and control characters - Per-file limit 200 MB, per-user quota 2 GiB (server-tunable)
Common errors / troubleshooting
Read
ERROR + DETAILfirst, then decide whether it's a parameter problem, a permission problem, or a missing object. If a command exits non-zero, follow the house rule: stop, do not silently retry.
| Scenario | Typical stderr | Root cause | Action |
|---|---|---|---|
Illegal path (../empty segment/illegal char) | HTTP 400 + DETAIL: error=bad_path, message=... | remote-path violates the whitelist | Switch to a normal relative path, e.g. skills/demo/SKILL.md |
| Object does not exist | HTTP 404 + DETAIL: error=not_found, message=... | Target file/dir is missing | Run tf list --prefix ... to confirm, then retry |
| TTL out of range | ERROR: --ttl-days must be <= 60 or --ttl-seconds ... | CLI argument out of range (front-loaded check) | Use a value inside the allowed range |
| Not authorized | HTTP 401/403 | Missing/invalid CONTAINER_JWT, or running outside the internal network | Run inside a Fly machine; confirm the JWT is injected |
Downloaded a directory without --zip | HTTP 400 (DETAIL mentions download mode) | Server requires zip mode for directories | tf get <dir> out.zip --zip |
| Deleted a non-empty directory without recursive | HTTP 400/409 | Directory is non-empty but --recursive wasn't passed | tf rm <dir> --recursive |
| File too large or directory zip exceeds the limit | HTTP 413 | Over the server's size limit | Split the directory/file and upload again |
Minimal regression checklist (P1 gates)
After every CLI output or error-handling change, run at least these five:
- Default output is compact (without
--verbose), yet put/get/fetch still includesha256and link still includesurl --verboseemits the full field set (envelope'sdata= server's raw payload)--jsonon success has every key:ok, error, message, detail, data--jsonon failure has every key:ok, error, message, detail, exit_code(whereerroris the server error code)- Exit codes stay consistent: success = 0, business failure = 1, usage error = 2
tf --json listandtf --json linksgo through the envelope (don't let the subparser's--jsonoverride)
Quick triage flow (share with collaborators)
tf list --prefix <target-prefix>: confirm the object actually exists.- Preserve the original stderr from the failing command (especially
DETAIL:). - On 4xx: fix the arguments — do not retry the same command.
- On 5xx / network error: wait briefly, then retry once.
Notes
- File TTL defaults to 7 days; downloads/overwrites each renew by 7 days; hard cap 60 days
- Short link TTL defaults to 1 hour, capped at 7 days
- To force a shorter TTL: pass
--ttl-days 1on upload (still bounded by the horizon) - Directory-zip default caps: 5000 files / 500 MB; over either limit → 413