paperclip-page · git:20260710.953b315 · 2026-07-10 · sha256 b524334197c39655

paperclip-page git:20260710.953b315A

Immutable. This exact content never changes and is served at /api/v1/blob/b524334197c39655.

---
name: paperclip-page
description: >
  Publish static HTML pages and asset folders to the Paperclip S3/CloudFront page
  host. Use when asked to deploy, host, or share a persistent page, viewer,
  prototype, report, or static site without here.now.
---

# Paperclip Page

Use this skill to publish a static directory to the configured Paperclip pages
host, for example `https://pages.paperclip.ing/<slug>/`.

## Requirements

- Source directory contains `index.html` at its root.
- `aws` CLI v2, `curl`, and `jq` are available on PATH for live publishes.
- Environment variables are configured:
  - `PAPERCLIP_PAGE_BUCKET`
  - `PAPERCLIP_PAGE_BASE_URL`
  - `AWS_REGION`
  - AWS credentials via Paperclip Secrets or an approved AWS vault
- Optional environment variables:
  - `PAPERCLIP_PAGE_DEFAULT_PREFIX`
  - `PAPERCLIP_PAGE_AWS_PROFILE`

## Workflow

1. Inspect the source directory and confirm it is public static content only.
2. Run `scripts/publish.sh <dir> --dry-run` to validate local structure and see
   the resolved URL/prefix.
3. Choose a slug:
   - Use `--slug <slug>` when the user gave a stable URL path.
   - Omit `--slug` to derive one from the source directory name.
4. Publish:

```bash
.agents/skills/paperclip-page/scripts/publish.sh ./site --slug my-page
```

5. Return the printed public URL and S3 prefix to the issue/user.

## Update Workflow

Updates are additive overwrites only. The helper never deletes remote objects.

```bash
.agents/skills/paperclip-page/scripts/publish.sh ./site --slug my-page --update
```

When the target prefix already exists, `--update` requires local ownership proof
from `./site/.paperclip-page/state.json` generated by an earlier publish from
that same source directory. Without that state, create a new slug instead of
overwriting another page.

## Safety Rules

- Publish public content only. Do not publish secrets, customer data, private
  company material, credentials, or internal logs.
- Never print AWS secret values.
- Never change bucket policy, IAM, DNS, CloudFront, or ACM settings from this
  skill. Setup belongs to an operator runbook, not the publish helper.
- Never upload outside the configured bucket and prefix.
- Never use `aws s3 sync --delete` or require `s3:DeleteObject` in v1.
- The helper forces `--no-follow-symlinks` and fails if any source symlink is
  present.
- The helper rejects hidden files and dot-segment paths except its own
  `.paperclip-page/state.json`.
- Slugs and prefix segments must use lowercase ASCII letters, digits, and
  hyphens only.
- Keep site-wide root objects such as `404.html` operator-managed; publishes
  always target `<slug>/...` or `<default-prefix>/<slug>/...`.

## Troubleshooting

- `Slug already exists`: choose a different slug or use `--update` from the
  original source directory containing `.paperclip-page/state.json`.
- `Missing index.html`: build the static site first or point the helper at the
  directory that contains the root HTML file.
- `Found symlink`: replace symlinks with real files before publishing.
- `AccessDenied`: confirm the uploader IAM policy allows `ListBucket`,
  `GetObject`, and `PutObject` for the configured bucket/prefix, and that the
  agent received the Paperclip Secrets.
- Public URL verification failed: check CloudFront deployment/DNS, object
  existence, and that the distribution uses HTTPS with the private S3 REST
  origin.

See `README.md` next to this skill for operator setup, AWS policy examples,
credential rotation, and install/attach commands.