# Droploft Doc

> Manage Droploft documents (drops): upload, list, get, content, share, publish, delete.

- Skill: `langgenius/droploft-doc` (Agent Skill)
- Install (CLI): `npx skillmds@latest add langgenius/droploft-doc`
- Raw SKILL.md: https://api.skillmd.com/api/skills/langgenius/droploft-doc/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: langgenius (https://skillmd.com/u/langgenius)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/langgenius/droploft-doc

---


# Droploft v2 CLI — Document Skill

A **drop** is a single document. It belongs to exactly one **loft**. This skill covers everything that happens to drops after they are created.

## Concepts

- `loft_id` — required for write ops; defaults to `profile.loft_id` set by `loft +switch`.
- `kind` — `markdown` or `html`. The CLI auto-detects from extension and content prefix.
- `status` — `processing` (just uploaded) → `published` (worker finished optimization).
- A successful upload returns a `share_token` and `share_url` (default share is enabled at creation).
- Publish is asynchronous — the CLI polls `GET /v1/tasks/:id` until `status` ∈ `{success, failed, cancelled}`.

## Layer 1 flows

### Upload a file

```bash
droploft doc +upload ./report.md
droploft doc +upload report.html --title "Q4 Plan" --loft <loft-id>
droploft doc +upload README.md --no-wait     # return as soon as publish enqueues
```

Sequence:
1. Read file, hash, derive title (override with `--title`).
2. `POST /v1/documents` → `{document_id, upload_url, share_token, share_url}`.
3. PUT raw bytes to the presigned URL with `content-type: text/html|text/markdown`.
4. `POST /v1/documents/:id/publish` → `{task_id}`.
5. Poll `GET /v1/tasks/:task_id` (default deadline 120 s).

### List drops in a loft

```bash
droploft doc +list                       # uses profile.loft_id
droploft doc +list --loft <id> --limit 20
```

## Layer 2 resource verbs

```bash
droploft documents list                                # current loft, scriptable
droploft documents get <doc-id>                        # detail incl. workspace/owner/share
droploft documents content <doc-id>                    # latest published content
droploft documents share-link <doc-id>                 # current share-link settings
droploft documents update-share <doc-id> --data '{"share_enabled":false}'
droploft documents publish <doc-id>                    # enqueue publish/optimize
droploft documents delete <doc-id>                     # move to trash
droploft documents trash                               # list trashed drops
droploft documents restore <doc-id>                    # restore from trash
droploft documents purge <doc-id>                      # permanent delete
droploft documents shared-with-me
```

Combine with `--format json --jq '.[].id'` to feed pipelines.

## Patterns

### Idempotent publish from CI

```bash
ID=$(droploft doc +upload ./build/index.html --no-wait --format json | jq -r .data.document_id)
# … later, after build settles
droploft documents publish "$ID"
```

### Disable share for a sensitive drop

```bash
droploft documents update-share <doc-id> --data '{"share_enabled":false}'
```

### Diagnose a failed publish

```bash
droploft tasks list --format table         # find the failing task_id
droploft tasks get <task-id>               # full row incl. error_message
droploft tasks retry <task-id>             # re-enqueue
```

## Common errors

| Type | Meaning | Recovery |
|---|---|---|
| `auth_required` (exit 3) | token missing/revoked | `droploft auth login` |
| `not_found` (exit 4) | drop doesn't exist or no read access | check `documents list` / loft membership |
| `conflict` (exit 5) | save race | retry with the latest base revision |
| `validation` (exit 2) | bad body — check `droploft schema get documents.create` |

## Limits & gotchas

- Files larger than the workspace plan trigger HTTP 413; envelope `error.message` includes the upgrade hint.
- `update-share` body shape is `{share_enabled, password?, expires_at?, max_views?}`.
- After a `delete`, the doc is hidden from `documents list` but remains in `documents trash` until purged.

