{
  "markdown": "<p align=\"center\">\n  <img src=\"assets/logo.svg\" width=\"112\" height=\"112\" alt=\"aispace logo\">\n</p>\n\n<h1 align=\"center\">aispace</h1>\n\n<p align=\"center\">\n  <strong>Secure temporary file sharing for AI agents and humans.</strong><br>\n  A scriptable CLI with expiring links, predictable JSON, and optional local age encryption.\n</p>\n\n<p align=\"center\">\n  <a href=\"https://aispace.sh\">Website</a> ·\n  <a href=\"https://aispace.sh/docs\">Documentation</a>\n</p>\n\n<p align=\"center\">\n  <a href=\"https://github.com/aispace-sh/aispace-client/releases/latest\"><img src=\"https://img.shields.io/github/v/release/aispace-sh/aispace-client?style=flat-square&color=FFD700\" alt=\"Release\"></a>\n  <a href=\"https://github.com/aispace-sh/aispace-client/actions/workflows/ci.yml\"><img src=\"https://img.shields.io/github/actions/workflow/status/aispace-sh/aispace-client/ci.yml?branch=main&style=flat-square&label=Go%20CI\" alt=\"Go CI\"></a>\n  <img src=\"https://img.shields.io/badge/Go-1.26+-00ADD8?style=flat-square&logo=go&logoColor=white\" alt=\"Go 1.26+\">\n  <a href=\"LICENSE\"><img src=\"https://img.shields.io/badge/license-MIT-blue?style=flat-square\" alt=\"MIT license\"></a>\n</p>\n\n<p align=\"center\">\n  <img src=\"assets/demo.gif\" width=\"760\" alt=\"Example terminal session uploading a report and receiving an expiring aispace link\">\n</p>\n\n[aispace.sh](https://aispace.sh) is a bot-friendly file drop for outputs that are too large,\nstructured, or temporary for chat. The open-source client is deliberately easy to automate: one\nbinary, stable exit codes, streaming uploads, and share URLs printed on a predictable final line.\n\n- **Built for agents:** stable JSON on supported commands, documented errors, stdin support, and\n  explicit noninteractive flags for automation. Secret-bearing handoff commands remain interactive.\n- **Short-lived by design:** file expiration, separately expiring links, revocation, and optional\n  per-link download caps.\n- **Private when needed:** sealed asynchronous transfers encrypt filenames, file metadata, and\n  content locally; their master key never reaches aispace. The existing age X25519 flow remains\n  available for recipient-key workflows.\n\nSealed transfers, agent identities, device pairing, and adaptive durable-first intent are\nexperimental surfaces. Ordinary uploads and durable R2 storage continue to work alongside them.\n\nThe hosted service is operated separately. This repository contains the client, agent skill, and\nintegration examples—not the server, billing system, deployment configuration, or customer data.\n\n## Try it in 60 seconds\n\nInstall the latest release:\n\n```sh\ncurl -fsSL https://aispace.sh/install.sh | sh\n```\n\nAuthenticate with a key created in the aispace dashboard, then store a file:\n\n```sh\naispace login --key ask_...\naispace upload report.pdf --json\n```\n\nOn a Pro account, add a separately expiring public handoff:\n\n```sh\naispace upload report.pdf --link --link-expires 1h --max-downloads 1\n```\n\nThe URL is printed last on its own line, making it easy for an agent or shell script to capture.\nAdd `--json` for a stable machine-readable response. An abridged response looks like:\n\n```json\n{\"file\":{\"id\":\"...\",\"name\":\"report.pdf\"},\"link\":{\"url\":\"https://aispace.sh/d/...\",\"expires_at\":1757003600}}\n```\n\nOther installation channels:\n\n```sh\nnpm install -g @aispace-sh/cli\nbrew install aispace-sh/tap/aispace\ngo install github.com/aispace-sh/aispace-client@latest\n```\n\nPin the shell installer with `AISPACE_VERSION=v1.2.3`. Release binaries support macOS, Linux, and\nWindows on amd64 and arm64. The shell installer supports macOS and Linux; use npm on Windows.\n\n<div align=\"center\">\n  <a href=\"https://x.ai/bot/suv5xSPPbQmzi02LF7Z9Z\">\n    <img src=\"assets/grok-bot-mark.svg\" width=\"96\" height=\"96\" alt=\"Grok Bot\">\n  </a>\n  <h3>Using Grok Bot?</h3>\n  <p>Give Grok Bot a fast, bot-friendly way to share files with aispace.</p>\n  <p>\n    <a href=\"https://x.ai/bot/suv5xSPPbQmzi02LF7Z9Z\"><strong>Add the aispace bot to Grok Bot →</strong></a>\n  </p>\n</div>\n\n---\n\n## Give aispace to an agent\n\nThe repository includes a reusable Codex-compatible skill. Clone the repository and link the skill\ninto your personal Codex skills directory:\n\n```sh\ngit clone https://github.com/aispace-sh/aispace-client.git\nmkdir -p ~/.codex/skills\nln -s \"$PWD/aispace-client/skills/aispace\" ~/.codex/skills/aispace\n```\n\nRestart Codex, then ask it to use `aispace` when it needs to hand you a report, archive, image, or\nother generated artifact. The skill defaults to account-private storage unless you request a public\nlink, prefers short expirations, and treats encryption identities as credentials.\n\n### Model Context Protocol (MCP)\n\nThe native CLI also exposes ten typed MCP tools over local stdio. Create a separately scoped bot\nkey in the dashboard, export it in the environment that launches Codex, and add:\n\n```toml\n[mcp_servers.aispace]\ncommand = \"aispace\"\nargs = [\"mcp\", \"serve\"]\nenv_vars = [\"AISPACE_KEY\", \"AISPACE_URL\", \"AISPACE_ALLOWED_ROOTS\"]\nstartup_timeout_sec = 10\ntool_timeout_sec = 120\ndefault_tools_approval_mode = \"writes\"\n\n[mcp_servers.aispace.tools.aispace_create_link]\napproval_mode = \"prompt\"\n\n[mcp_servers.aispace.tools.aispace_revoke_link]\napproval_mode = \"prompt\"\n\n[mcp_servers.aispace.tools.aispace_delete_file]\napproval_mode = \"prompt\"\n```\n\nRun `codex mcp list` to verify the connection. The ChatGPT desktop app, Codex CLI, and Codex IDE\nextension on the same host share this configuration. Keep the key in a secret store or injected\nenvironment; never put its expanded value in a committed project file or command argument. See\n[`docs/CLI.md`](docs/CLI.md#mcp-server) for Claude Code and generic-host examples.\n\nFor custom agent runtimes, [`docs/LLM_USAGE.md`](docs/LLM_USAGE.md) includes a system-prompt snippet,\nOpenAI/Anthropic-compatible tool schemas, and a reference Python handler. See [`examples`](examples)\nfor runnable shell, CI, and encrypted-handoff recipes.\n\n## Common workflows\n\n```sh\n# Upload text from stdin and return an expiring public link (Pro).\necho \"hello\" | aispace upload - --name note.txt --link --link-expires 1h\n\n# Keep a file available only to this key.\naispace upload secret.txt --private\n\n# Share ciphertext; keep the generated age identity locally.\naispace upload secret.pdf --encrypt --identity-out secret.agekey --link\n\n# Authenticated handoff to another key on the same account—no public URL.\naispace upload notes.md --shared --json\n\n# Sealed multi-file handoff. The URL fragment holds the local decryption secret.\naispace transfer create report.pdf charts.png --sealed --link --expires 1d --max-downloads 1\n\n# Move that sealed transfer to a nearby browser/device with an expiring code.\naispace handoff offer \"$TRANSFER_ID\"\n# On the receiving CLI: aispace handoff receive J7KM-PQRT\n\n# Pin an agent and deliver without exposing a bearer decryption link.\naispace recipient add \"$RECIPIENT_INVITATION\"\naispace recipient verify research-agent --fingerprint \"$RECIPIENT_FINGERPRINT\"\naispace transfer create report.pdf --sealed --to research-agent --from my-agent --expires 7d\naispace inbox receive \"$DELIVERY_ID\" --yes\n\n# Paste the link interactively, inspect its private manifest, then decrypt and verify.\naispace transfer receive\n\n# Receive, manage, and revoke.\naispace ls --json\naispace download <file_id> --output ./file\naispace download <file_id> --output ./file --verify   # check the recorded SHA-256\naispace link <file_id> --expires 30m --max-downloads 1\naispace revoke <link_id>\naispace rm <file_id>\n```\n\nFollow [`docs/SECURE_HANDOFFS.md`](docs/SECURE_HANDOFFS.md) for sealed bundles, trusted agent\ninboxes, device pairing, adaptive R2 fallback, and recovery. The complete command reference is in\n[`docs/CLI.md`](docs/CLI.md); the HTTP contract is in [`docs/API.md`](docs/API.md).\n\n`upload` accepts `--name`, `--expires`, `--content-type`, `--sha256`, `--link`, `--link-expires`,\n`--max-downloads`, `--private`, `--shared`, `--encrypt`, `--recipient`, and `--identity-out`.\nUploads stream from disk. Encrypted uploads use age X25519 locally and store ciphertext as\n`<name>.age`; the secret identity is never sent to the API.\n\n`transfer create` uses `aispace-sealed-v1`: AES-256-GCM authenticated chunks and an encrypted\nmanifest support multiple files, ranged retry, and a verified receipt. `transfer receive` accepts\nthe secret from its prompt, `--token-file`, or `AISPACE_TRANSFER_TOKEN`; avoid putting a full\nfragment link or token in a process argument on shared systems.\n\n`transfer create --json` omits bearer links and tokens unless `--include-secret` is explicit, and\nsecret-inclusive JSON must be redirected rather than written to a terminal. `handoff encode`\nlikewise accepts the protected prompt, `--token-file`, or `AISPACE_TRANSFER_TOKEN`.\n\nWith `--json`, errors also remain structured and are written to stderr. `upload --link --json`\nreturns `{\"file\": File, \"link\": ShareLink}`; encrypted uploads add an `\"encryption\"` object.\n\n## Configuration\n\nPrecedence: flag > environment > config file > default.\n\n| Setting | Flag | Env | File key | Default |\n|---|---|---|---|---|\n| API key | `--key` | `AISPACE_KEY` | `key` | — |\n| Server | `--url` | `AISPACE_URL` | `url` | `https://aispace.sh` |\n\n`AISPACE_AGE_IDENTITY` supplies a decryption identity when `decrypt --identity-file` is omitted.\nIt is deliberately not accepted as a command-line value.\n\nConfig file: `$XDG_CONFIG_HOME/aispace/config.json` (default `~/.config/aispace/config.json`), written with\nmode 0600. A warning is printed if the file is readable by others. `AISPACE_CONFIG` overrides the path.\n\nDurations (`--expires`, `--link-expires`) accept Go syntax plus a `d` suffix: `30m`, `24h`, `7d`, `1d12h`,\nor a bare number of seconds. Omitting them uses the server defaults (7 days for files, 1 hour for\nPro public links).\n\n## File permissions and links\n\nFile visibility controls authenticated key access. A public link is a separate capability: creating\none requires a Pro account and makes that one file available to anyone holding the URL.\n\n| File mode | Who can access it? | File lifetime | Public-link lifetime | Download cap | Exposure if access leaks |\n|---|---|---|---|---|---|\n| `private` | Uploading key only | 7 days by default; maximum 7 days on Free or 30 days on Pro | None | Account monthly limit | Private files belonging to that key, until deletion or expiry |\n| `account` | Every active key on the account | 7 days by default; maximum 7 days on Free or 30 days on Pro | None | Account monthly limit | Account-shared files, until deletion or expiry |\n| `private` + public link | Uploading key and anyone with the URL | Maximum 30 days because links require Pro | 1 hour by default; maximum 30 days and never beyond file expiry | Optional per-link cap | Only the linked file, until link expiry, revocation, exhaustion, file deletion, or file expiry |\n| `account` + public link | Account keys and anyone with the URL | Maximum 30 days because links require Pro | 1 hour by default; maximum 30 days and never beyond file expiry | Optional per-link cap | URL access ends with the link; account keys retain access until file deletion or expiry |\n| Client-encrypted file | Visibility controls ciphertext access; only age identity holders can decrypt it | Same limits as the selected file mode | Same Pro-only limits when a link is created | Optional per-link cap | Plaintext exposure requires both the ciphertext and the age identity |\n\nAvailable duration syntax includes `30s`, `15m`, `1h`, `36h`, and `7d`.\n\nA file becomes unavailable when its file lifetime ends. A link can end sooner because it expired,\nwas revoked, or reached its download cap. Deleting the file immediately ends authenticated key\naccess and every associated public link.\n\n## Exit codes\n\n| Code | Meaning |\n|---|---|\n| 0 | success |\n| 1 | generic error (network, 4xx/5xx not listed below) |\n| 2 | usage error |\n| 3 | authentication (401, or no key configured) |\n| 4 | quota / size (402, 413) |\n| 5 | rate limited (429) — idempotent GETs sleep `Retry-After` (max 30s) and retry once |\n\nErrors go to stderr as `error: <message> (<code>)`; with `--json` they are a JSON object\n`{\"error\":{\"code\",\"message\",\"status\",\"details\",\"exit_code\"}}` on stderr instead.\n\n## Development\n\n```sh\ngo test -race ./... && go vet ./... && test -z \"$(gofmt -l .)\"\ngo build -ldflags \"-X main.version=0.0.0-dev\" -o aispace .\n(cd npm && npm test && npm pack --dry-run)\n```\n\nThe test suite uses local HTTP fixtures and does not require an aispace key. Contributions are\nwelcome—start with [`CONTRIBUTING.md`](CONTRIBUTING.md), check the [`ROADMAP.md`](ROADMAP.md), and\nreview the [`CHANGELOG.md`](CHANGELOG.md). Focused bug reports and feature proposals can use the\nrepository's structured issue forms.\n\nReleases are cut through the manual GitHub Actions workflow. GoReleaser builds checksummed macOS,\nLinux, and Windows binaries, updates the Homebrew tap, publishes `@aispace-sh/cli` to npm, verifies\nthe installed MCP server on all three platforms, and finally publishes `sh.aispace/mcp` to the\nofficial Registry. See [`RELEASE.md`](RELEASE.md) for publisher configuration, resumable MCP-only\npublication, and the release checklist.\n\n## Security\n\nPlease report vulnerabilities privately through GitHub Security Advisories. Do not open a public\nissue containing a credential, private link, or customer data. See [`docs/SECURITY.md`](docs/SECURITY.md).\n",
  "bytes": 13356,
  "sha": "4f00fb91ea1141c13ae94301445f8b4d316fb88599c8b86cdd2ed709520eb873",
  "repo_slug": "aispace-sh/aispace-client",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_sh_aispace_mcp_1fe66d81/readme"
}