Workspace format
A workspace is one folder. Everything Postguy stores is in it. There is no database and no account. The files are pretty-printed JSON, so they diff well in Git. For the user view, see Workspace. This page is the file reference. The source is crates/store.
Directory layout
<workspace>/
postguy.json schema, collection order, environment order, active environment id
collections/<id>.json one file per collection (folders and requests nested inside)
environments/<id>.json one file per environment
globals.json the globals, an environment-shaped file
protos/<name>/... .proto files imported for gRPC
files/ the default working directory for file references
assets/<collection id>/... the collection's Assets folder
history.jsonl request history, one JSON object per line
.trash/ deleted items and their metadata
.postguy/
secrets.json values of variables marked secret (0600 on Unix)
cookies.json the persistent cookie jar
responses/ cached response bodies
runs/<collection id>/<run id>.json stored collection runs
lock the workspace lock
.postguy-config/
settings.json settings
session.json open tabs, drafts, window geometry
recent.json recently opened workspaces
- Opening a workspace creates the folder and
collections/,environments/,protos/,files/,.trash/,.postguy/and.postguy/responses/. It then takes the lock and createspostguy.jsonif it is missing. Other paths are created on first use. - Every file the store writes is written atomically. A temporary file in the same folder is synced, then renamed over the target. The previous version stays next to it as
<name>.bak(one generation only). A failed write leaves the old file in place. .postguy-config/sits inside the workspace in the desktop app (apps/postguy/src/main.rs) and in the automation sessions ofpostguy-cli(crates/automation/src/session.rs). The whole state moves with the folder.
postguy.json
{
"schema": "postguy/workspace/1",
"collectionOrder": ["<collection id>"],
"environmentOrder": ["<environment id>"],
"activeEnvironmentId": "<environment id>"
}
| Key | Meaning |
|---|---|
schema | Always postguy/workspace/1 today. Missing means the same value. |
collectionOrder | Collection ids in sidebar order. Files in collections/ that are not listed are appended after, sorted by id. |
environmentOrder | The same for environments/. |
activeEnvironmentId | The selected environment. Omitted when none is selected. Cleared when that environment is deleted. |
Unknown keys are kept and written back.
Collection and environment files
Both use camelCase keys. Every field has a default, so partial files load.
| File | Top-level keys |
|---|---|
collections/<id>.json | id, name, description, variables, auth, scripts, pinnedEnvironment, favourite, items |
environments/<id>.json, globals.json | id, name, color, variables |
itemsholds folders and requests as objects tagged withitemType(folderorrequest) anditem.- Folders carry
id,name,description,variables,auth,scriptsand their ownitems. - Requests carry
id,name,description,kind(the HTTP, gRPC or WebSocket body) andexamples.
- Folders carry
- A variable row is
key,value,description,enabled(defaulttrue) andsecret(defaultfalse). - Unknown keys are preserved (they round-trip), so an older version does not truncate files from a newer one.
Ids
Files are named after ids. An id used as a file name must match [A-Za-z0-9_-]{1,64}. No dots, slashes or spaces are allowed, so an id cannot escape its folder.
- Postguy generates UUID text.
- Imported Postman files often carry short ids like
env-1. These are accepted. - Run ids and the collection id in
.postguy/runs/may be up to 128 characters of the same set.
Secrets
A variable with secret: true keeps only the flag in the collection, environment or globals file. Its value is blanked there and stored in .postguy/secrets.json.
{
"<owner id>": { "<variable key>": "<value>" }
}
| Owner id | Holds |
|---|---|
| an environment id | that environment's secret variables |
globals | secret global variables |
| a collection id or folder id | that collection's or folder's secret variables, and OAuth 2.0 tokens from its auth block |
| a request id | OAuth 2.0 tokens of that request's auth block |
- OAuth 2.0 tokens are stored under the keys
oauth2.accessandoauth2.refresh. - An empty secret value removes the key.
- Deleting an environment or collection (including its folders) removes its owner entries.
- The file is set to mode
0600on Unix. On Windows no extra permission step is taken. - The file is read back into the variables when the workspace loads.
.postguy/secrets.json is plain JSON. Do not commit .postguy/. The source says an OS keychain is a deferred decision.History
history.jsonl has one JSON object per line, each wrapped as {"entry": {...}}.
| Entry key | Meaning |
|---|---|
id | Entry id. |
timeMs | Unix time in milliseconds. |
request | Snapshot of the request as sent. |
status | HTTP status, when there was a response. |
durationMs | Round-trip time. |
sizeBytes | Response body size (decoded size for compressed responses). |
responseRef | Reference into .postguy/responses/ when responses are saved. |
- Only sends you make yourself are recorded. The collection runner sends without writing history.
- The file keeps the newest 5000 entries. Appends are a single line write until the cap. After that, the file is rewritten without the oldest entry.
- A line that does not parse (for example a torn last line after a crash) is skipped when reading.
- Deleting one entry or clearing history rewrites the file atomically.
Trash
Deleting a collection or environment moves its file into .trash/. The content goes under an id of the form t<unix ms>-<pid> (a numbered -N.trash name is used on a collision), with a sidecar <id>.meta.json.
{
"id": "t1730000000000-4242",
"original": "/path/to/workspace/collections/<id>.json",
"kind": "collection",
"deletedAtMs": 1730000000000,
"sizeBytes": 2048
}
- Restore moves the file back to
original. If something already exists there, the file is restored withrestoredadded before the extension. - Deleting a folder or request writes a JSON snapshot
.trash/item-<nanos>.jsonwith the keyskind,collectionId,itemId,deletedAtanditem.
item-<nanos>.json) are written, but the Trash panel does not list them yet. Its source says they appear once the item-restore path lands.Lock
.postguy/lock contains pid=<pid> and start=<unix ms> lines.
- A second process that opens the same workspace is refused while the owner process is alive and the lock is younger than 3 minutes. The error is "workspace already open by pid N; close that instance or remove
if it is gone". - A lock whose process is gone, or that is older than 3 minutes, is taken over.
- The lock is never renewed. So a workspace that stays open for more than 3 minutes can be opened by a second process.
- The lock file is removed when the workspace closes.
- Liveness is checked with
ps -pon Unix andtaskliston Windows. If that check cannot run, the process is assumed alive.
Stored runs
.postguy/runs/<collection id>/<run id>.json holds one collection-runner result. Run ids sort by time. Only the newest 20 per collection are kept. Older files are deleted when a new run is saved. A stored run is read back with a 32 MiB cap.
Read caps and corrupt files
| File | Read cap |
|---|---|
Collection, environment, globals, postguy.json | 100 MiB |
settings.json, session.json, .postguy/secrets.json | 8 MiB |
| Stored run | 32 MiB |
A file over its cap is refused with an error rather than loaded.
| Situation | Result |
|---|---|
A collection, environment, globals or postguy.json file does not parse | The file is renamed to <name>.corrupt-<nanoseconds> and the app continues with an empty default. The user is told. The bytes stay for manual salvage; the previous version is also in <name>.bak if one exists. |
settings.json does not parse | Quarantined the same way; defaults are used. |
session.json does not parse | Quarantined; the session starts fresh. |
.postguy/cookies.json does not parse or is not an object | Quarantined; the jar starts empty. |
.postguy/secrets.json does not parse | Quarantined and the open fails with "secrets file was corrupt; moved to ..."; restore the file from secrets.json.bak or recreate the secret values. |
| A missing file | Treated as a fresh default; nothing is reported. |
To recover from a quarantined file, copy <name>.bak (or the .corrupt-* file after repair) back to <name>.
UI control channel
The opt-in local HTTP channel that lets postguy-cli inspect and drive the running desktop app: launch, control file, endpoints, set keys, command ids and limits.
Feature status
What is shipped, partial, planned or out of scope in each area, from the parity file, plus the known limitations in plain terms.