- name
- code-storage
- description
- Agent skill for interacting with code.storage, a managed Git infrastructure layer. Provides repository creation, branching, commits, file access, diffs, search, notes, GitHub sync, ephemeral branches, and forking through a RESTful HTTP API authenticated with customer-signed JWTs. Every repo operation scoped per-JWT.
MCP server: https://code.storage/docs/mcp
Docs index: https://code.storage/docs/llms.txt
Official SDKs (in this repository):
- TypeScript / JavaScript: `@pierre/storage` (npm)
- Python: `pierre-storage` (PyPI; import `pierre_storage`)
- Go: `github.com/pierrecomputer/sdk/packages/code-storage-go`
## TypeScript custom HTTP transport
`new GitStorage({ name, key, fetch })` (also `CodeStorage` and `createClient`)
accepts an optional `fetch: typeof globalThis.fetch`. It applies to all SDK HTTP
calls, including repository handles, downloads, and streaming commit uploads.
The default is global fetch; the SDK adds no automatic retries. Callers own retry
limits, backoff, cancellation, and safe body replay. Do not blindly retry writes
or reuse consumed streaming request bodies. This option does not affect Git CLI
traffic. See `packages/code-storage-typescript/README.md` for a read-only retry
example. Python and Go do not use this TypeScript option.
# ENVIRONMENT SETUP
## Required Environment Variables
| Variable | Description | Example |
|-------------------------|----------------------------------------------------------------|--------------------------------------------------|
| `ORG_NAME` | Your organization identifier (subdomain slug) | `acme` |
| `PIERRE_PRIVATE_KEY` | PEM-encoded EC (ES256) or RSA (RS256) private key | `-----BEGIN PRIVATE KEY-----\n...` |
| `CODE_STORAGE_BASE_URL` | Derived base URL for HTTP API | `https://api.acme.code.storage/api/v1` |
| `CODE_STORAGE_TOKEN` | JWT minted for current operation (per-repo or org-wide) | `eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9...` |
Export for curl sessions:
```bash
export ORG_NAME="your-org"
export CODE_STORAGE_BASE_URL="https://api.${ORG_NAME}.code.storage/api/v1"
export CODE_STORAGE_TOKEN="YOUR_JWT_TOKEN"
```
## JWT Token Structure
Every request requires a JWT signed with your private key. Tokens are per-repository
(except `org:read` which is org-wide).
```json
{
"iss": "your-org", // Organization identifier
"sub": "@pierre/storage", // Subject (the SDKs set this to the package name)
"repo": "team/project", // Repository the token grants access to
"scopes": ["git:read", "git:write"],
"refs": [ // Optional per-ref policy rules (first match wins)
["refs/heads/main", ["no-push"]],
["refs/heads/feature/*", ["no-force-push"]]
],
"iat": 1723453189,
"exp": 1723456789
}
```
JWT header: `{ "alg": "ES256", "typ": "JWT" }` (RS256 and EdDSA also supported)
### Policy Operations
| Op string | SDK constant | Effect |
|------------------|------------------------------------------------------------------------------|-------------------------------------------------------|
| `no-force-push` | TS `OP_NO_FORCE_PUSH` / Py `OP_NO_FORCE_PUSH` / Go `storage.OpNoForcePush` | Rejects force pushes / non-fast-forward ref updates. |
| `no-push` | TS `OP_NO_PUSH` / Py `OP_NO_PUSH` / Go `storage.OpNoPush` | Rejects any push to matching refs. |
| `verify-sig` | TS `OP_VERIFY_SIG` / Py `OP_VERIFY_SIG` / Go `storage.OpVerifySig` | Rejects pushes introducing commits without a valid signature from a registered signing key. |
#### Per-ref policies (preferred, use this for new code)
The `refs` claim is an **ordered** array of `[pattern, [ops...]]` tuples.
Rules are evaluated in declaration order. The first pattern that matches the ref
wins. Patterns may be fully-qualified refs (`refs/heads/main`), prefix globs
(`refs/heads/feature/*`, `refs/tags/*`), or `*` for every ref. Short branch names
like `main` are normalized to `refs/heads/main` on verify. The policies are
accepted by every URL-minting method and every ref-mutating REST method via the
SDK option `refPolicies` (TS), `ref_policies` (Py), `RefPolicies` (Go).
#### Repo-wide `ops` (legacy, do not use in new code)
The optional top-level `ops` claim applies to every ref. On verify it is folded
into the catch-all `*` rule. It is merged into an existing `*` entry in the ref
policies when one is present, or appended as a new trailing `*` rule otherwise.
Only available on the URL-minting methods (`getRemoteURL` /
`getEphemeralRemoteURL` / `getImportRemoteURL`). Use
`refPolicies: [{ pattern: '*', ops: [...] }]` instead.
```typescript
await repo.getRemoteURL({
refPolicies: [
{ pattern: 'refs/heads/main', ops: [OP_NO_PUSH] },
{ pattern: '*', ops: [OP_NO_FORCE_PUSH] },
],
});
```
```python
await repo.get_remote_url(
ref_policies=[
{"pattern": "refs/heads/main", "ops": [OP_NO_PUSH]},
{"pattern": "*", "ops": [OP_NO_FORCE_PUSH]},
],
)
```
```go
repo.RemoteURL(ctx, storage.RemoteURLOptions{
RefPolicies: storage.RefPolicyList{
{Pattern: "refs/heads/main", Ops: storage.Ops{storage.OpNoPush}},
{Pattern: "*", Ops: storage.Ops{storage.OpNoForcePush}},
},
})
```
### Permission Scopes
| Scope | Grants | Required By |
|--------------|---------------------------------|------------------------------------------------|
| `git:read` | clone, fetch, pull, read API | GET file/branch/commit/diff/grep endpoints |
| `git:write` | push, write API (includes read) | POST/DELETE commit/branch/note endpoints |
| `repo:write` | create/delete repositories | POST /repos, DELETE /repos/delete |
| `org:read` | list all repos in org | GET /repos (list) |
### Git Remote URL Format
```
https://t:{JWT}@{ORG_NAME}.code.storage/{REPO_ID}.git
```
Username is always `t`. Password is the JWT.
# QUICK-REFERENCE ENDPOINT TABLE
| Goal | Method | Endpoint | Scope Required |
|-------------------------------|----------|-----------------------------------|-----------------|
| **REPOSITORIES** | | | |
| Create repository | POST | `/repos` | `repo:write` |
| List all repositories | GET | `/repos` | `org:read` |
| Get repository metadata | GET | `/repo` | (repo in JWT) |
| Delete repository | DELETE | `/repos/delete` | `repo:write` |
| **BRANCHES** | | | |
| Create branch | POST | `/repos/branches/create` | `git:write` |
| List branches | GET | `/repos/branches` | `git:read` |
| Get branch diff | GET | `/repos/branches/diff` | `git:read` |
| Preview merge | GET | `/repos/merge/preview` | `git:read` |
| Merge branches | POST | `/repos/merge` | `git:write` |
| Delete branch | DELETE | `/repos/branches` | `git:write` |
| **COMMITS** | | | |
| Create commit (file blobs) | POST | `/repos/commit-pack` | `git:write` |
| Create commit from diff/patch | POST | `/repos/diff-commit` | `git:write` |
| List commits | GET | `/repos/commits` | `git:read` |
| Get commit | GET | `/repos/commit` | `git:read` |
| Get commit diff | GET | `/repos/diff` | `git:read` |
| Restore branch to commit | POST | `/repos/restore-commit` | `git:write` |
| **FILES** | | | |
| List files at ref | GET | `/repos/files` | `git:read` |
| List files with metadata | GET | `/repos/files/metadata` | `git:read` |
| Get file content (stream) | GET/HEAD | `/repos/file` | `git:read` |
| Blame file at ref | GET | `/repos/blame` | `git:read` |
| Search content (grep) | POST | `/repos/grep` | `git:read` |
| Download archive (tar.gz) | POST | `/repos/archive` | `git:read` |
| **TAGS** | | | |
| Create tag | POST | `/repos/tags` | `git:write` |
| List tags | GET | `/repos/tags` | `git:read` |
| Delete tag | DELETE | `/repos/tags` | `git:read`+`git:write` |
| **NOTES** | | | |
| Create note on commit | POST | `/repos/notes` (action:"add") | `git:write` |
| Append to note | POST | `/repos/notes` (action:"append") | `git:write` |
| Get note for commit | GET | `/repos/notes?sha=SHA` | `git:read` |
| Delete note | DELETE | `/repos/notes` | `git:write` |
| List notes refs | GET | `/repos/notes/refs` | `git:read` |
| **GIT SYNC** | | | |
| Pull from upstream | POST | `/repos/pull-upstream` | `git:write` |
| Detach upstream | DELETE | `/repos/base` | `git:write` |
| **GENERIC GIT SYNC** | | | |
| Create Git credential | POST | `/repos/git-credentials` | `repo:write` |
| Update Git credential | PUT | `/repos/git-credentials` | `repo:write` |
| Delete Git credential | DELETE | `/repos/git-credentials` | `repo:write` |
All endpoints: `BASE_URL = https://api.{org}.code.storage/api/v1`
View on GitHub