https://github.com/pocketenv-io/pocketenv-clojure
Clojure SDK for Pocketenv
https://github.com/pocketenv-io/pocketenv-clojure
agent clojure microvm sandbox
Last synced: about 2 months ago
JSON representation
Clojure SDK for Pocketenv
- Host: GitHub
- URL: https://github.com/pocketenv-io/pocketenv-clojure
- Owner: pocketenv-io
- License: mit
- Created: 2026-04-02T11:41:15.000Z (2 months ago)
- Default Branch: main
- Last Pushed: 2026-04-05T16:18:20.000Z (about 2 months ago)
- Last Synced: 2026-04-05T17:29:09.054Z (about 2 months ago)
- Topics: agent, clojure, microvm, sandbox
- Language: Clojure
- Homepage: https://pocketenv.io
- Size: 36.1 KB
- Stars: 2
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# pocketenv-clojure
[](https://github.com/pocketenv-io/pocketenv-clojure/actions/workflows/ci.yml)
[](https://clojars.org/io.pocketenv/pocketenv)
Clojure SDK for the [Pocketenv](https://pocketenv.io) sandbox platform.
## Installation
Add to your `deps.edn`:
```clojure
{:deps io.pocketenv/pocketenv {:mvn/version "0.1.3-SNAPSHOT"}}
```
## Configuration
Set one of the following before making any calls:
| Method | Details |
|-----------------|------------------------------------------------|
| Env var | `POCKETENV_TOKEN=` |
| Token file | `~/.pocketenv/token.json` → `{"token": "..."}` |
| Per-call option | Pass `:token "..."` in the opts map |
Optional env vars:
```
POCKETENV_API_URL — API base URL (default: https://api.pocketenv.io)
POCKETENV_PUBLIC_KEY — server public key for client-side encryption (hex-encoded)
POCKETENV_STORAGE_URL — storage base URL for file transfers (default: https://sandbox.pocketenv.io)
```
## Quick start
```clojure
(require '[pocketenv-io.pocketenv :as pocketenv]
'[pocketenv-io.sandbox :as sandbox])
;; Create, start, run a command, then clean up
(-> (pocketenv/create-sandbox "my-box")
(sandbox/start)
(sandbox/wait-until-running)
(sandbox/exec "echo" ["hello from pocketenv"])
;; {:ok #ExecResult{:stdout "hello from pocketenv\n" :stderr "" :exit-code 0}}
)
```
All functions return `{:ok value}` on success or `{:error reason}` on failure. The `sandbox/*` operations also accept an `{:ok sandbox}` result directly so they can be chained with `->` without unwrapping.
---
## Sandbox lifecycle
### Create
```clojure
;; Minimal — uses the default openclaw base image on Cloudflare
(pocketenv/create-sandbox "my-box")
;; => {:ok #Sandbox{:id "..." :name "my-box" :status :stopped ...}}
;; With options
(pocketenv/create-sandbox "my-box"
{:provider "daytona"
:repo "https://github.com/acme/my-app"
:keep-alive true})
```
### Start / Stop / Delete
```clojure
(def sb (pocketenv/create-sandbox "my-box"))
(sandbox/start sb)
(sandbox/stop sb)
(sandbox/delete sb)
```
### Wait until running
```clojure
(-> (pocketenv/create-sandbox "ci-runner")
(sandbox/start)
(sandbox/wait-until-running {:timeout-ms 120000 :interval-ms 3000}))
```
---
## Running commands
```clojure
(let [result (-> (pocketenv/get-sandbox "my-box")
(sandbox/exec "ls" ["-la" "/"]))]
(println (get-in result [:ok :stdout])))
;; Run a Clojure test suite
(-> (pocketenv/get-sandbox "my-box")
(sandbox/start)
(sandbox/wait-until-running)
(sandbox/exec "clojure" ["-M:test"]))
;; => {:ok #ExecResult{:stdout "..." :stderr "" :exit-code 0}}
```
`ExecResult` fields: `:stdout`, `:stderr`, `:exit-code`.
---
## Listing sandboxes
```clojure
;; Public sandbox catalog
(pocketenv/list-sandboxes)
;; => {:ok {:sandboxes [...] :total 42}}
;; With pagination
(pocketenv/list-sandboxes {:limit 10 :offset 20})
;; Sandboxes belonging to a specific actor (DID or handle)
(pocketenv/list-sandboxes-by-actor "alice.pocketenv.io")
(pocketenv/list-sandboxes-by-actor "did:plc:abc123")
```
---
## Exposing ports
```clojure
;; Expose port 3000 and get a public preview URL
(-> (pocketenv/get-sandbox "my-box")
(sandbox/expose 3000 {:description "Web server"}))
;; => {:ok "https://preview.pocketenv.io/..."}
;; List all exposed ports
(-> (pocketenv/get-sandbox "my-box")
(sandbox/list-ports))
;; => {:ok [#Port{:port 3000 :description "Web server" :preview-url "..."}]}
;; Remove a port
(-> (pocketenv/get-sandbox "my-box")
(sandbox/unexpose 3000))
```
---
## VS Code Server
```clojure
(-> (pocketenv/get-sandbox "my-box")
(sandbox/vscode))
;; => {:ok "https://preview.pocketenv.io/.../vscode/..."}
```
---
## Secrets
Secrets are encrypted client-side before transmission.
```clojure
;; Add a secret
(pocketenv/add-secret "sandbox-id" "DATABASE_URL" "postgres://...")
;; Or via the sandbox pipe
(-> (pocketenv/get-sandbox "my-box")
(sandbox/set-secret "API_KEY" "sk-..."))
;; List secrets (names only — values are never returned)
(pocketenv/list-secrets "sandbox-id")
;; => {:ok [#Secret{:id "..." :name "DATABASE_URL" :created-at "..."}]}
;; Delete a secret by id
(pocketenv/delete-secret "secret-id")
```
---
## SSH keys
Private keys are encrypted client-side before transmission.
```clojure
;; Store a key pair
(pocketenv/put-ssh-keys "sandbox-id" private-key-str public-key-str)
;; Or via the sandbox pipe
(-> (pocketenv/get-sandbox "my-box")
(sandbox/set-ssh-keys private-key-str public-key-str))
;; Retrieve
(pocketenv/get-ssh-keys "sandbox-id")
;; => {:ok #SshKey{:id "..." :public-key "..." :private-key "..." :created-at "..."}}
```
---
## Tailscale
```clojure
;; Store a Tailscale auth key (must start with "tskey-auth-")
(pocketenv/put-tailscale-auth-key "sandbox-id" "tskey-auth-...")
;; Or via the sandbox pipe
(-> (pocketenv/get-sandbox "my-box")
(sandbox/set-tailscale-auth-key "tskey-auth-..."))
;; Retrieve
(pocketenv/get-tailscale-auth-key "sandbox-id")
;; => {:ok #TailscaleAuthKey{:id "..." :auth-key "..." :created-at "..."}}
```
---
## Copying files
Upload a local file or directory into a sandbox, download a sandbox path to local disk, or copy directly between two sandboxes — all through storage, with no manual archiving required.
```clojure
;; Upload a local directory to the sandbox
(-> (pocketenv/get-sandbox "my-box")
(sandbox/upload "./my-project" "/workspace"))
;; Upload a single file
(-> (pocketenv/get-sandbox "my-box")
(sandbox/upload "./config.json" "/app/config.json"))
;; Download a sandbox path to a local directory
(-> (pocketenv/get-sandbox "my-box")
(sandbox/download "/workspace/output" "./output"))
;; Copy a path from one sandbox to another (no local I/O)
(-> (pocketenv/get-sandbox "source-box")
(sandbox/copy-to "dest-sandbox-id" "/workspace" "/workspace"))
```
All three functions return `:ok` on success or `{:error reason}` on failure and are pipe-safe — they accept a bare `Sandbox` or an `{:ok sandbox}` result from a previous step.
---
## Actor / profile
```clojure
;; Your own profile (requires authentication)
(pocketenv/me)
;; => {:ok #Profile{:did "did:plc:..." :handle "alice" :display-name "Alice" ...}}
;; Any actor's profile
(pocketenv/get-profile "alice.pocketenv.io")
(pocketenv/get-profile "did:plc:abc123")
```
---
## Error handling
Every function returns `{:ok value}` or `{:error reason}`. Use `if-let` or pattern matching:
```clojure
(let [result (pocketenv/get-sandbox "does-not-exist")]
(if-let [sb (:ok result)]
(println "Found:" (:name sb))
(println "Error:" (:error result))))
```
When chaining with `sandbox/*`, passing `{:error ...}` into any operation throws an `ExceptionInfo`, keeping failures explicit.
---
## License
MIT