@seekrit/paperclip-plugin 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/shared.js +3 -3
  2. package/package.json +12 -12
package/dist/shared.js CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region package.json
2
- var version = "0.1.0";
2
+ var version = "0.2.1";
3
3
  //#endregion
4
4
  //#region src/skills.generated.ts
5
5
  const MANAGED_SKILLS = [
@@ -11,7 +11,7 @@ const MANAGED_SKILLS = [
11
11
  "markdown": "---\nname: seekrit-secrets\ndescription: Store and use end-to-end encrypted secrets with seekrit instead of putting values in .env files, shell commands, or source. Use whenever a task involves an API key, token, password, connection string, or .env file — storing a credential a human just handed over, running a command that needs one, wiring up an app's configuration, or when a value is missing and the temptation is to hardcode it or go hunting for it. Also covers setting seekrit up from nothing (signup, org, app, environment) and granting an environment to a service token.\nlicense: MIT\ncompatibility: Needs network access to seekrit's API. The local server runs through npx (Node 20+); the hosted server needs no install.\n---\n\n# Secrets with seekrit\n\nseekrit is an end-to-end encrypted secrets manager: the server stores only\nciphertext, and values are decrypted in *this* process, next to the credential.\nThat single fact produces one hard rule and one preferred verb.\n\n## The rule\n\n**A secret value must not come to rest anywhere it can be read again.**\n\n- Never write a value into `.env`, a config file, a Dockerfile, a Kubernetes\n manifest, or source — even temporarily, even in a file you plan to delete.\n- Never put a value in a command line (`export KEY=…`, `curl -H \"Authorization:\n Bearer sk-…\"`). It lands in shell history, in process listings, and in this\n transcript.\n- Never print a value to show your work, and never quote one back to the user\n who pasted it.\n- Never route around a missing value. If a `.env` read is denied or a file is\n absent, do **not** try `docker compose config`, `git log -p`, a lockfile, a CI\n log, a cloud console, or another secrets CLI to reconstruct it. Ask, or use the\n tools below.\n\nIf you have already broken this rule in this session — a value in a file, a\ncommand, or your output — say so plainly and treat that credential as needing\nrotation.\n\n## The preferred verb: run, don't read\n\nAlmost every task that \"needs a secret\" actually needs a *process* that has the\nsecret. Inject it and never see it:\n\n| Where you are | Do this |\n| --- | --- |\n| MCP client | `run_command { command: \"pnpm\", args: [\"dev\"] }` |\n| A shell | `seekrit run -- pnpm dev` |\n| Dockerfile / CI / container | `seekrit-run -- ./server` (static binary) |\n| Kubernetes | the seekrit ESO chart, not a copied Secret |\n\n`run_command` resolves the environment, injects every granted secret as an\nenvironment variable in the child process only, and returns the exit code and\ncaptured output. **It never returns values.** Precedence, highest first: process\nenv → `.env` overlay → app environment → composed groups.\n\nRead a value with `get_secret { name, reveal: true }` only when a human\nexplicitly asked to see it, or when it must be pasted into a system with no\nother way in. Say out loud that you are doing it, and prefer\n`get_secret { name }` (which confirms existence without the value) for checks.\n\n`export_env` writes a resolved `.env`. It exists for runtimes that genuinely\ncannot be wrapped. Treat it as the last resort it is, and never as a\nconvenience.\n\n## Decision table\n\n| Situation | Tool |\n| --- | --- |\n| Run something that needs secrets | `run_command` / `seekrit run` |\n| A human pasted a new credential | `set_secret { name, value }` — then don't echo it |\n| Rotate a value | `set_secret` again; history is kept, `list_secret_versions` shows it |\n| \"What config does this app have?\" | `list_secrets` — names and metadata, never values |\n| \"Is `STRIPE_KEY` set?\" | `list_secrets`, or `get_secret { name }` without `reveal` |\n| Wire a new app or service | `create_app` → `create_env` → `set_secret` |\n| Give a deployment read access | `create_token` then `grant_env` |\n| Share config across apps | groups — see [references/model.md](references/model.md) |\n| Try a risky config change | `create_branch` on the environment, then `run_command { branch }` |\n| Needs a *third-party API key it must not read* | the **seekrit-agent-keys** skill |\n\n## Storing a value you were handed\n\n```\nset_secret { app: \"storefront\", env: \"production\", name: \"STRIPE_SECRET_KEY\", value: \"<the value>\" }\n```\n\nThen confirm by name only: \"stored `STRIPE_SECRET_KEY` in storefront/production.\"\nA value can reference another with `${OTHER_SECRET}`, so build connection\nstrings from parts rather than duplicating a password.\n\nImporting an existing `.env` is one call — `seekrit secrets import .env` — after\nwhich **delete the file** and tell the user you did.\n\n## If you have no credential yet\n\nThe hosted server needs no account to connect. Call `signup` on it:\n\n```\nsignup { orgName: \"Acme Storefront\", orgSlug: \"acme-storefront\" }\n→ { credential: { clientId, clientSecret } }\n```\n\nName the org after the real project or company — a human claims it by that name\nlater, so `test` makes it unmanageable. The `clientSecret` is shown once.\nPersist it so both servers keep working:\n\n```bash\nseekrit login --client-id <id> --client-secret <secret>\n```\n\nThat writes `~/.config/seekrit/config.json`, which the local server reads with\nno environment plumbing. (`SEEKRIT_CLIENT_ID` / `SEEKRIT_CLIENT_SECRET` in the\nenvironment work too, if the client passes its environment through.) Machine\ncredentials auto-mint an admin token, so one credential drives both servers.\n\n## Two servers, one credential\n\nThis plugin installs both. They are split along the encryption boundary, and\nthe split is enforced, not conventional:\n\n- **`seekrit`** (local, stdio) — anything touching a *value*: `set_secret`,\n `get_secret`, `run_command`, `export_env`, `create_env`, `create_token`,\n `grant_env`, KMS operations, database leases. Decryption happens here because\n this is where the key is.\n- **`seekrit-cloud`** (hosted, `mcp.seekrit.dev`) — metadata and management with\n no install: orgs, apps, environments, groups, composition, members, audit,\n billing, secret *names*. It cannot decrypt anything and will refuse a service\n token outright.\n\nStart on the local server; it can finish a secrets task end to end. Use the\nhosted one when you cannot install anything, or for management and audit. If you\nare on the hosted server and hit a wall, `local_tool_for { operation }` names the\nlocal tool to use instead.\n\n## Further reading\n\n- [references/model.md](references/model.md) — orgs, apps, environments, groups,\n composition, branches, references, and how to model a tenant.\n- [references/cli.md](references/cli.md) — the CLI equivalent of every tool\n here, for shells, CI, and containers.\n",
12
12
  "files": [{
13
13
  "path": "references/cli.md",
14
- "content": "# CLI equivalents\n\nInstall: `npm install -g @seekrit/cli` (or `npx @seekrit/cli`). For containers\nand CI there is `seekrit-run`, a static single binary with the same injection\nbehaviour and no Node dependency.\n\n## Authenticate\n\n```bash\nseekrit login --client-id <id> --client-secret <secret> # machine credential\nseekrit login --token skt_… # existing service token\nseekrit login # browser approval, for a human\nseekrit whoami\n```\n\nCredentials land in `~/.config/seekrit/config.json`. `SEEKRIT_TOKEN`,\n`SEEKRIT_CLIENT_ID` / `SEEKRIT_CLIENT_SECRET`, and `SEEKRIT_API_URL` override it.\n\n## Run something with secrets injected\n\n```bash\nseekrit run -- pnpm dev\nseekrit run --env staging -- ./migrate\nseekrit run --branch pr-1234 -- pnpm test\nseekrit run --with platform=sandbox -- ./server # override one group's slice\nseekrit run --explain -- true # where each variable came from\n```\n\n`--explain` prints resolution provenance to stderr and never prints values. It\nis the right way to debug \"why is this variable wrong\".\n\n## Secrets\n\n```bash\nseekrit secrets list # names and metadata only\nseekrit secrets set STRIPE_KEY # reads the value from stdin\nseekrit secrets set TLS_KEY --file key.pem # from a file, no shell quoting\nseekrit secrets get NAME # prints the value — think first\nseekrit secrets import .env # then delete the file\nseekrit secrets history NAME\nseekrit secrets restore NAME 3\nseekrit secrets rm NAME\n```\n\nOmit the value argument so it arrives on stdin, or use `--file` for a PEM or\nJSON credential. Passing the value inline puts it in shell history.\n\n## Structure\n\n```bash\nseekrit init # writes seekrit.json for this project\nseekrit app create / list / show\nseekrit env create / list / groups\nseekrit group create / env create # shared secret bags and their slices\nseekrit branch create <slug> --from production --ttl 7d\nseekrit token create / list / revoke\nseekrit grant --token skt_… --app storefront --env production\nseekrit audit\n```\n\n## In CI and containers\n\nGive the job a token scoped to one environment, then wrap the command:\n\n```bash\nseekrit-run -- ./deploy.sh\n```\n\nNothing is written to disk, and the child process is the only thing that ever\nholds the values. For GitHub Actions there is a dedicated action; for Kubernetes\nuse the seekrit External Secrets Operator chart rather than copying values into\na `Secret` by hand.\n"
14
+ "content": "# CLI equivalents\n\nInstall: `npm install -g @seekrit/cli` (or `npx @seekrit/cli`). For containers\nand CI there is `seekrit-run`, a static single binary with the same injection\nbehaviour and no Node dependency.\n\n## Authenticate\n\n```bash\nseekrit login --client-id <id> --client-secret <secret> # machine credential\nseekrit login --token skt_… # existing service token\nseekrit login # browser approval, for a human\nseekrit whoami\n```\n\nCredentials land in `~/.config/seekrit/config.json`. `SEEKRIT_TOKEN`,\n`SEEKRIT_CLIENT_ID` / `SEEKRIT_CLIENT_SECRET`, and `SEEKRIT_API_URL` override it.\n\n## Run something with secrets injected\n\n```bash\nseekrit run -- pnpm dev\nseekrit run --env staging -- ./migrate\nseekrit run --branch pr-1234 -- pnpm test\nseekrit run --with platform=sandbox -- ./server # override one group's slice\nseekrit run --explain -- true # where each variable came from\n```\n\n`--explain` prints resolution provenance to stderr and never prints values. It\nis the right way to debug \"why is this variable wrong\".\n\n## Secrets\n\n```bash\nseekrit secrets list # names and metadata only\nseekrit secrets set STRIPE_KEY # reads the value from stdin\nseekrit secrets set TLS_KEY --file key.pem # from a file, no shell quoting\nseekrit secrets get NAME # prints the value — think first\nseekrit secrets import .env # then delete the file\nseekrit secrets history NAME\nseekrit secrets restore NAME 3\nseekrit secrets rm NAME\n```\n\nOmit the value argument so it arrives on stdin, or use `--file` for a PEM or\nJSON credential. Passing the value inline puts it in shell history.\n\nNone of these name an environment because a service token is bound to one — the\ncommands above are complete as written. Add `--app <slug> --env <slug>` only to\nreach a different environment (as a signed-in human always must).\n\n## Structure\n\n```bash\nseekrit init --org acme --app storefront # writes seekrit.json for this project\nseekrit app create / list / show\nseekrit env create / list / groups\nseekrit group create / env create # shared secret bags and their slices\nseekrit branch create <slug> --from production --ttl 7d\nseekrit token create / list / revoke\nseekrit grant --token skt_… --app storefront --env production\nseekrit audit\n```\n\n## In CI and containers\n\nGive the job a token scoped to one environment, then wrap the command:\n\n```bash\nseekrit-run -- ./deploy.sh\n```\n\nNothing is written to disk, and the child process is the only thing that ever\nholds the values. For GitHub Actions there is a dedicated action; for Kubernetes\nuse the seekrit External Secrets Operator chart rather than copying values into\na `Secret` by hand.\n"
15
15
  }, {
16
16
  "path": "references/model.md",
17
17
  "content": "# The resource model\n\n```\norganization\n└── application (a codebase / service)\n └── environment (production, staging, dev …)\n └── secret (name → encrypted value, versioned)\ngroups (org-scoped reusable secret bags, also per-environment)\n```\n\nAn application environment resolves to **its own secrets plus the groups it\ncomposes**. Values layer, lowest precedence first:\n\n```\ngroup secrets < app-env secrets < .env overlay < process env\n```\n\nAfter merging, `${OTHER_SECRET}` references inside values are expanded — so a\n`DATABASE_URL` can be assembled from a group's host and the app's password\nwithout duplicating either.\n\n## Groups\n\nUse a group when two or more apps need the same value (a shared database, an\nobservability key, an internal CA). A group has its own environments keyed by\nslug; at resolve time each composed group is matched to the environment whose\nslug equals the app environment's, so composing `platform` into\n`storefront/production` pulls `platform/production`.\n\n- `create_group` / `create_group_env` / `compose_group` / `uncompose_group`\n- `list_env_groups` shows what an environment pulls in; `list_group_envs` shows\n a group's slices.\n\nPrefer a group over copying a value into five apps. Copies drift and rotate\nbadly.\n\n## Branches\n\nA branch is an ephemeral fork of an environment: it inherits everything and\noverrides only what differs, then deletes itself. Use one for a preview deploy,\na pull request, or a risky config experiment — never a real environment named\n`pr-1234`.\n\n- `create_branch { app, from: \"production\", slug: \"pr-142\" }`, then `run_command { branch }`\n- `delete_branch` when done; `list_branches` to find strays.\n\n## Service tokens and grants\n\nA token is a principal with a keypair, not a password. Creating one does not\ngrant it anything; `grant_env` wraps that environment's data key to the token's\npublic key, which is what lets it decrypt.\n\n- `create_token` (add `admin: true` only for a management credential)\n- `grant_env { token, app, env }` — one grant per environment the token reads\n- `revoke_token` immediately; `list_tokens` to audit\n\nA deployment should hold a token scoped to exactly one environment. An admin\ntoken belongs on a developer machine or a management job, never in a running\nservice.\n\n## Temporary access (leases)\n\nFor a human or agent that needs a database *now* and should not keep it, mint a\nlease instead of handing over a stored credential: `create_pg_lease` /\n`create_mysql_lease` provision a scoped, expiring database user through a\ncustomer-hosted provisioner, and `revoke_pg_lease` / `revoke_mysql_lease` end it\nearly. `list_pg_targets` / `list_mysql_targets` show what can be leased.\n\nPrefer a lease over `get_secret reveal:true` on a database password. It expires\non its own, and the audit trail says who had it and when.\n\n## Modelling a multi-tenant agent\n\nIf one agent serves many customers and each needs its own credentials, pick by\nhow the tenants differ:\n\n| Shape | Model it as | Why |\n| --- | --- | --- |\n| Tenants share the code, differ in credentials | one **environment per tenant** under one app | independent grants, independent audit, independent rotation |\n| Most config is shared, a few keys differ | one group composed by every tenant environment | rotate the shared parts once |\n| Access should expire after a task | a **lease** | nothing to revoke later |\n| Tenant credential must never be readable by the agent | the **seekrit-agent-keys** skill (proxy) | the agent holds a placeholder, not a key |\n\nResolve per run, not per process: fetch for the tenant you are serving now and\nlet it go afterwards. Do not build a process-wide map of every tenant's secrets\n— that turns one compromised request into a full breach.\n"
@@ -78,7 +78,7 @@ const manifest = {
78
78
  description: "End-to-end encrypted secrets for Paperclip agents: inject credentials into a run without the run — or Paperclip — ever holding a value.",
79
79
  author: "seekrit",
80
80
  categories: ["connector"],
81
- minimumHostVersion: "2026.817.0",
81
+ minimumHostVersion: "2026.831.1",
82
82
  capabilities: [
83
83
  "agent.tools.register",
84
84
  "secrets.read-ref",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seekrit/paperclip-plugin",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "description": "seekrit for Paperclip — agent tools that inject end-to-end encrypted secrets into a run without the run ever holding a value, plus the seekrit skills and a company secrets panel.",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -27,21 +27,21 @@
27
27
  ],
28
28
  "homepage": "https://seekrit.dev/docs/guides/ai-agents/paperclip",
29
29
  "license": "MIT",
30
+ "dependencies": {
31
+ "@paperclipai/plugin-sdk": "2026.831.1"
32
+ },
33
+ "devDependencies": {
34
+ "@types/node": "^26.1.0",
35
+ "@types/react": "^19.2.18",
36
+ "react": "^19.2.8",
37
+ "tsdown": "^0.22.3",
38
+ "vitest": "^4.1.11"
39
+ },
30
40
  "scripts": {
31
41
  "gen": "node gen-skills.mjs src/skills.generated.ts",
32
42
  "build": "pnpm gen && tsdown && tsdown --config tsdown.ui.config.ts",
33
43
  "dev": "pnpm gen && tsdown --watch",
34
44
  "test": "pnpm gen && vitest run",
35
45
  "typecheck": "pnpm gen && tsc --noEmit"
36
- },
37
- "dependencies": {
38
- "@paperclipai/plugin-sdk": "2026.817.0"
39
- },
40
- "devDependencies": {
41
- "@types/node": "^26.1.0",
42
- "@types/react": "^19.2.17",
43
- "react": "^19.2.0",
44
- "tsdown": "^0.22.3",
45
- "vitest": "^4.1.9"
46
46
  }
47
- }
47
+ }