Install
$ agentstack add skill-chen3feng-agent-skills-agent-work-artifacts-layout ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Agent work artifacts: where do they go?
When to use
Any task where the agent produces files that are not the user's intended deliverable: PR body drafts for gh pr create --body-file, throwaway repro_*.py / check_*.sh scripts, audit reports, analysis dumps, temporary fixtures. Without a convention these end up either polluting the working tree (triggering "do I need to delete this?" round-trips) or getting lost across sessions even when they had reuse value.
Problem
Three recurring failure modes:
- PR body files left in the repo root (e.g.
pr_body.md),
forcing the user to confirm deletion after every PR.
- One-off scripts committed to random places — sometimes in
the repo root, sometimes nowhere — making future contributors unsure whether they are project tooling or dead weight.
- Fixed temp paths like
/tmp/pr_body.mdthat collide between
parallel agent sessions.
Solution
Route every artifact through this four-way decision:
1. Single-use (PR body, gh intermediate, shell pipe)?
→ system temp via mktemp -t .XXXXXX.
(POSIX: $TMPDIR or /tmp; Windows: %TEMP%)
2. Repo-scoped helper, human-authored, part of project lifecycle?
→ scripts/ (or tools/ if the repo already uses that)
with argparse CLI, docstring, usage example.
3. Repo-scoped helper, agent-authored, reviewed and reusable?
→ .agent/tools/ (tracked subdirectory of the agent working area,
see the four-cell layout below)
4. General-purpose, useful across projects?
→ offer to publish as a GitHub Gist.
5. Agent working notes / drafts / caches NOT meant for sharing?
→ .agent/scratchpad/ | .agent/artifacts/ | .agent/context/
(gitignored, local-only)
If none apply, delete the file rather than leaving it ambiguous.
.agent/ four-cell layout
.agent/ is not a single bucket — split it by lifetime and tracking intent:
| Subdirectory | Purpose | Tracked? | | --- | --- | --- | | .agent/scratchpad/ | Free-form notes, pseudo-code, drafts. | No | | .agent/artifacts/ | Generated deliverables (exported docs, images, one-off reports). | No | | .agent/tools/ | Reviewed agent-authored helpers for this repo. | Yes | | .agent/context/ | Project index / knowledge-base caches / embeddings. | No |
The tracked subset is surfaced via a whitelist-style .gitignore (see Example). Keeping .agent/tools/ in Git lets genuinely reusable agent-authored helpers survive across sessions without mixing with the project's human-authored scripts/.
scripts/ vs .agent/tools/
They coexist, with clear provenance separation:
scripts/(if/when the repo has one) = human-authored core
tooling that's part of the project's normal lifecycle (release, lint, bootstrap).
.agent/tools/= helpers written by an agent, reviewed, and
kept because they proved useful. Provenance is tagged at the directory level — no silent promotion to scripts/, only via a dedicated "graduation" PR.
Example
Right way — PR body in system temp
body=$(mktemp -t pr_body.XXXXXX.md)
# write body via the editor tool, targeting "$body"
gh pr create --repo / --base --head \
--title '' --body-file "$body"
Wrong way — PR body in repo root
# Leaves pr_body.md in the working tree after the PR is filed.
# The user then has to approve its deletion in a follow-up turn.
vi pr_body.md
gh pr create --body-file pr_body.md
Right way — commit message via repo-local scratchpad
In an agent terminal, commit flows that chain mktemp + git commit
rmoften trigger human-confirmation prompts on every commit.
.agent/scratchpad/ sidesteps this by removing both mktemp and the trailing rm:
MSG=.agent/scratchpad/commitmsg.$$.txt
printf '%s\n' 'Subject line' '' 'Body paragraph.' > "$MSG"
git commit -F "$MSG"
# .agent/scratchpad/ is gitignored; sweep occasionally.
This applies to commit messages, not PR bodies — PR bodies should still use system temp (see previous example) because they are one-shot and benefit from OS-level cleanup.
See [shell-heredoc-and-multiline-strings](../shell-heredoc-and-multiline-strings/SKILL.md) for when to choose each temp location.
Right way — repo-scoped helper that others might reuse
/scripts/check_doc_consistency.py # committed, with argparse + docstring
Right way — agent working area with whitelist gitignore
/.agent/
README.md # tracked: layout convention for contributors
scratchpad/ # ignored: notes, drafts
artifacts/ # ignored: generated deliverables
context/ # ignored: indexes, caches
tools/
README.md # tracked: intake standard
.py # tracked: reviewed agent-authored helpers
.sh # tracked
Corresponding .gitignore block (whitelist pattern — blanket ignore first, then un-ignore each tracked path):
/.agent/*
!/.agent/README.md
!/.agent/tools/
/.agent/tools/*
!/.agent/tools/*.py
!/.agent/tools/*.sh
!/.agent/tools/README.md
Verify with git check-ignore -v after editing — it's the only way to be sure reopens line up with blanket ignores.
Intake standard for .agent/tools/
Because helpers here are tracked, they need a quality bar. Every committed script should have:
- Provenance header naming the agent session.
argparseCLI with--help.- Dry-run default;
--apply/--writeto mutate. - Module-level docstring with a real usage example.
- Stdlib-only (or deps the project already has).
- UTF-8 safe (
encoding="utf-8"on file I/O). - Introduced in its own dedicated PR, not smuggled in.
Document this in a .agent/tools/README.md at repo setup time.
Pitfalls
- The convention is inert without an actual
.gitignore. Writing
this skill, or a .agent/README.md, or just telling the agent to "put drafts in .agent/scratchpad/" does not make those files ignored. Without a committed .gitignore entry they show up as ?? in git status, and a single git add -A (easy to type when rushing a commit) sweeps them into the tree. Verify on day one:
``bash git check-ignore -v .agent/scratchpad/anyfile.txt # expect: .gitignore::.agent/ .agent/scratchpad/anyfile.txt ``
If that command prints nothing, the convention is a lie and the next git add -A will betray it. This skill's own repo shipped without a .gitignore for its first nine PRs — nobody got bitten only because every commit used explicit git add . Don't rely on that.
.agent/is convention, not project API. A tracked
.agent/README.md explaining the layout is fine (similar in spirit to .github/'s own README), but nothing in the build, tests, or CI should read from .agent/. If a file needs to run on fresh clones or other contributors' machines, it doesn't belong here — promote it to scripts/ with a dedicated PR.
- Whitelist gitignore is order-sensitive. The blanket
/.agent/* must come before the !-prefixed reopens, otherwise the reopens have no effect. Always verify with git check-ignore -v for both a tracked path and an ignored path before committing.
- Use
.agent/scratchpad/for commit-message drafts, not PR bodies.
Commit messages are produced many times per session and benefit from a fixed local path (no mktemp, no rm, fewer agent-terminal confirmation prompts). PR bodies are one-shot, often contain the final version of release notes, and should stay in system temp so the OS cleans them up — a lingering draft under .agent/scratchpad/ invites confusion about which version made it to GitHub.
- **Do not rely on
.agent/scratchpad/,/artifacts/, or
/context/ for anything needed on another machine** — they are gitignored. Only .agent/tools/ survives cloning.
- Windows:
/tmpandmktempare not portable. Prefer
tempfile.gettempdir() from Python when the caller might be on Windows.
- Do not confuse
scripts/withcontrib/. In PostgreSQL /
Git, contrib/ means "distributed alongside core but not part of it". Unless the target repo already uses that convention, stick with whichever of scripts/ or tools/ the repo already has.
- **Do not silently "graduate"
.agent/tools/scripts to
scripts/.** Promotion is a conscious decision that warrants a PR of its own (with a new provenance line: "originally authored by agent, audited and graduated"). Silent moves destroy the provenance signal the .agent/tools/ location exists to preserve.
- Industry precedent: CPython, Django, Kubernetes, Rust, LLVM
all ship a top-level scripts/ or tools/. No mainstream project formalises an "AI agent working area" yet; .agent/ is the convention this skill proposes, sitting alongside existing local caches like .pytest_cache/, .mypy_cache/, .idea/.
See also
- [github-pr-via-gh-cli](../github-pr-via-gh-cli/SKILL.md)
- [shell-heredoc-and-multiline-strings](../shell-heredoc-and-multiline-strings/SKILL.md)
- [workspace-path-constraints](../workspace-path-constraints/SKILL.md)
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: chen3feng
- Source: chen3feng/agent-skills
- License: Apache-2.0
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.