Postguy
Reference

Workspace format

The on-disk layout of a Postguy workspace folder, the JSON files in it, and the rules for ids, secrets, history, trash, caps and corrupt files.

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 creates postguy.json if 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 of postguy-cli (crates/automation/src/session.rs). The whole state moves with the folder.
The app holds the workspace lock while it is open. Close Postguy before you edit files by hand. Otherwise a later save from the app can overwrite your change.

postguy.json

{
  "schema": "postguy/workspace/1",
  "collectionOrder": ["<collection id>"],
  "environmentOrder": ["<environment id>"],
  "activeEnvironmentId": "<environment id>"
}
KeyMeaning
schemaAlways postguy/workspace/1 today. Missing means the same value.
collectionOrderCollection ids in sidebar order. Files in collections/ that are not listed are appended after, sorted by id.
environmentOrderThe same for environments/.
activeEnvironmentIdThe 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.

FileTop-level keys
collections/<id>.jsonid, name, description, variables, auth, scripts, pinnedEnvironment, favourite, items
environments/<id>.json, globals.jsonid, name, color, variables
  • items holds folders and requests as objects tagged with itemType (folder or request) and item.
    • Folders carry id, name, description, variables, auth, scripts and their own items.
    • Requests carry id, name, description, kind (the HTTP, gRPC or WebSocket body) and examples.
  • A variable row is key, value, description, enabled (default true) and secret (default false).
  • 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 idHolds
an environment idthat environment's secret variables
globalssecret global variables
a collection id or folder idthat collection's or folder's secret variables, and OAuth 2.0 tokens from its auth block
a request idOAuth 2.0 tokens of that request's auth block
  • OAuth 2.0 tokens are stored under the keys oauth2.access and oauth2.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 0600 on Unix. On Windows no extra permission step is taken.
  • The file is read back into the variables when the workspace loads.
Secret values are not encrypted at rest. They are kept out of collection and environment files so those can be committed, but .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 keyMeaning
idEntry id.
timeMsUnix time in milliseconds.
requestSnapshot of the request as sent.
statusHTTP status, when there was a response.
durationMsRound-trip time.
sizeBytesResponse body size (decoded size for compressed responses).
responseRefReference 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 with restored added before the extension.
  • Deleting a folder or request writes a JSON snapshot .trash/item-<nanos>.json with the keys kind, collectionId, itemId, deletedAt and item.
The store defines a 30-day retention window and a purge function. Nothing in the app or the CLI calls the purge, so trashed files stay until you delete them. The Trash panel lists collections and environments and restores them. Item snapshots (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 -p on Unix and tasklist on 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

FileRead cap
Collection, environment, globals, postguy.json100 MiB
settings.json, session.json, .postguy/secrets.json8 MiB
Stored run32 MiB

A file over its cap is refused with an error rather than loaded.

SituationResult
A collection, environment, globals or postguy.json file does not parseThe 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 parseQuarantined the same way; defaults are used.
session.json does not parseQuarantined; the session starts fresh.
.postguy/cookies.json does not parse or is not an objectQuarantined; the jar starts empty.
.postguy/secrets.json does not parseQuarantined 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 fileTreated 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>.

Copyright © 2026