Pico API Client
Minimal, local-first API client for VS Code. No account, no cloud.
Features
- Three sidebar views, top to bottom: Workspaces, Environments, APIs (cross-IDE shared storage at
~/.config/pico/data.json).
- The active workspace (and the environment that is applied) get their icon painted with the theme accent colour, so the current context is visible at a glance.
- Everything auto-saves (like Yaak): request edits, environment variables and workspace/folder settings are written ~0.6 s after the last change, with a small
Saving… / Saved status in the toolbar and no Save button anywhere. Ctrl/Cmd+S flushes immediately and Send persists before sending. Edits made in the bulk (name: value) editor are part of what gets saved, even before you switch back to the table.
- Request editor modelled after Yaak:
Body · Params · Headers · Auth · Settings · Info (the Body and Auth tabs switch panes when the label is clicked; the small caret next to the label opens the type menu), with per-tab counts, drag-to-reorder rows, bulk (name: value) editing, header name/value autocomplete and variable chips. It opens on the body tab when the request has a body (Yaak behaviour) and on Params otherwise.
- Bodies: Url Encoded, Multi-Part (file parts), GraphQL, JSON, XML, Other, Binary File and No Body — switching type converts what you already typed and keeps the Content-Type header in sync.
- JSON bodies get syntax highlighting (keys, strings, numbers, booleans, null, punctuation, and variable references even inside strings), a Format button that pretty prints with two spaces and refuses to touch invalid input (the header shows
invalid JSON), two-space Tab indentation and a scroll-synced highlight layer.
- Auth: Inherit from Parent, No Auth, API Key, AWS Signature v4, Basic, Bearer, Digest, JWT Bearer, OAuth 1.0 and OAuth 2.0 (client credentials, password, authorization code with PKCE via a localhost callback). NTLM is listed but not implemented yet.
- Inheritance: headers, auth and settings resolve request -> folder chain -> workspace, with built-in
User-Agent/Accept defaults shown as "Inherited".
- Settings: request timeout, TLS validation, redirect following, HTTP version (automatic / HTTP/1.1 / HTTP/2) and cookie handling.
- Cookie jar per workspace: cookies from
Set-Cookie are stored and replayed with RFC 6265 domain/path rules.
- DNS overrides per workspace, applied like
/etc/hosts entries (TLS still validates the original hostname).
- Environments: a base "Global Variables" set that always applies plus switchable environments. Variables are written as
${[ name ]}, ${name} or {{name}} and are resolved in the URL, params, headers, auth and body when sending.
- Environment editor (click an environment in the sidebar): rename, add/remove/reorder variables, bulk edit (
name: value), enable/disable rows, "Set as active" and delete. Variables that requests reference but nothing defines are listed with one-click add buttons, so an imported workspace can be made whole without guessing.
- Variable references are recognised in place: the URL field shows
knowledgeUrl/recall/search pills while it is unfocused (hover shows the resolved value, clicking opens the environment editor) and the raw ${[ name ]} template when focused.
- Params, Headers and form values do the same: the chip is rendered inside the value box (no extra row under it), hovering shows the resolved value and clicking opens the environment editor.
- Response viewer modelled after Yaak:
200 OK • 963 ms • 9.5 KB bar with a history button, then Response · Request · Headers (n/m) · Cookies · Timeline (n) tabs. It is contributed as a webview view in the panel dock (the Terminal/Problems area, Pico → Response), not as an editor tab, so it never occupies an editor column; the status is mirrored in the view description and the tab bar stays put while the body scrolls.
- Dropdown menus stay inside the panel even when it is docked narrow: they are width capped, scroll internally and the ones anchored at the right edge (response history, more actions) open leftwards.
- Workspace settings open from a gear button on the workspace row itself (
inline action) instead of a context menu entry.
- The response view is paired with the request editor: opening a request reveals it (showing that request's latest stored response, or "No response yet"), switching requests follows, and sending updates it without stealing the keyboard focus. Closing the request editor still cancels a running send; the dock itself stays where the user put it.
- Response: JSON with line numbers, syntax colouring and collapsible nodes, plus a
Response (Raw) view, Save to File and Copy Body.
- Request: the request that was sent (URL, headers, body).
- Headers: dashed Info / Request Headers / Response Headers sections with lower-cased names.
- Cookies: cookies that were sent and cookies received from
Set-Cookie.
- Timeline: resolved settings, method + path, outgoing headers, "Sending request to server", the status line, response headers and received chunks, each with a millisecond timestamp, plus a filter menu and
Copy Timeline.
- History: per-request list of past responses (status · time · size, grouped by day) that can be re-opened, with
Delete / Delete all.
- Requests are sent without connection pooling, so every send resolves DNS again (that is what makes DNS overrides and per-request timing reliable).
- Cancellation: closing the request editor or the response panel aborts the running send, the response panel has a Cancel button and Send All can be cancelled from the progress notification. Aborting tears the socket down immediately.
- Request settings: the request timeout applies to the auth handshake (Digest probe, OAuth 2.0 token request) too, workspace DNS overrides and the TLS setting are honoured on those requests as well.
~/.config/pico/data.json is written with write-then-rename, and a file that cannot be parsed is never overwritten: Pico keeps it, copies it aside and tells you where it is.
- Credentials (
Authorization, cookie, x-api-key, …) are masked in the stored response record and in the Timeline tab.
- Every generated page script is parsed at activation (
validatePageScripts): a syntax error used to leave a panel silently dead (tabs stop switching, Send does nothing), now it is reported in the log and as an error message.
- A cross-host redirect drops
Authorization, Cookie and friends before the next hop.
Menus and shortcuts
| Where |
Entries |
| Folder (right click) |
Folder Settings · Send All · Rename · Duplicate · Delete ── New HTTP Request · New GraphQL Request ── Export · Import |
| Request (right click) |
Send · Copy as Curl · Rename · Duplicate · Delete |
| Workspace (right click) |
Workspace Settings · Rename · Select Environment · Export · Clear Cookie Jar · Delete |
Shortcuts inside the APIs view: Cmd/Ctrl+D duplicate the selected node, Cmd/Ctrl+Enter send it (a folder sends everything inside), F2 rename. Move is done by dragging a folder or request onto another folder — drop it on empty space to move it back to the root.
When clause rule: every when in package.json uses exact equality only (view == … && viewItem == …). Regex operators (=~, !~) are banned because a negative regex evaluates to true when the context key is missing, which leaks menu entries into other extensions' tree views. Keep it that way when adding menus.
Workspace settings page
Opening Workspace Settings (workspace context menu, or the gear in the view title) shows an editor with tabs:
| Tab |
Contents |
| Workspace |
name, Markdown description, environment variables, Delete Workspace and the workspace id (copyable). |
| Settings |
local directory sync (writes a Yaak export of the workspace into a folder for backup/Git), workspace encryption (not implemented), request settings and cookie settings. |
| Headers |
built-in defaults plus this model's own headers, with the same pair editor as requests. |
| Auth |
pick an auth method to apply to every request in the workspace, or inherit/no auth. |
| DNS |
hostname -> IPv4/IPv6 overrides. |
Folder settings show the same tabs minus DNS, with the headers inherited from the workspace shown read-only.
Import Data
Run Pico: Import Data... from a view title, the command palette, or a folder context menu. Choose a file, drag one onto the drop zone, type a path, or paste a URL / raw content.
| Format |
Notes |
| Yaak |
Full workspace export (yaakSchema): workspaces, folder headers/auth/settings, HTTP requests and environments. gRPC/WebSocket requests are skipped. |
| Postman |
Collection v2.x (nested folders with their own auth/headers, auth, bodies, collection variables) and Postman environments. |
| OpenAPI 3 / Swagger 2.0 |
JSON or YAML. Operations are grouped by their first tag, servers/host become the base URL, and query/header/path parameters plus JSON/form bodies are generated from schema examples. |
| Insomnia |
Export v4 (resources) and the newer collection export, including base and sub-environments. |
| curl |
One or more commands. Handles -X, -H, -d/--data*, --json, -F, -u, -G, -b, -A, -e, --url, short-flag clusters and line continuations. |
| .http / .rest |
JetBrains / REST Client style files with ### sections and @variables. |
Workspace-level formats (Yaak, Postman collection, Insomnia) create a new workspace by default; request-level formats (OpenAPI, curl, .http) are added to the current workspace. Both can be overridden with the Import into selector.
Export
Run Pico: Export... from a view title, a workspace/folder context menu, or the command palette. Pick a format, then save it to a file or copy it to the clipboard.
| Format |
Notes |
| Yaak export |
Round-trips through Pico's own importer and into Yaak. |
| Postman collection (v2.1) |
Folders, auth, bodies and collection variables. |
| OpenAPI 3.0 |
Paths derived from the requests (common prefix becomes the server URL), query/header parameters, request bodies and security schemes. |
| Insomnia export |
v4 resources format. |
| curl script |
One command per request with variables resolved. |
| .http file |
### sections, @variables from the base environment. |
Languages
The UI follows VS Code's display language. English is the source language and the lookup key; Simplified Chinese ships as the only translation. Runtime strings go through t() (extension host) and L10N() (in-page scripts, the dictionary is injected with the page), declarative strings use %pico.*% plus package.nls.json / package.nls.zh-cn.json. npm run check:i18n fails when a key used in code is missing from the dictionary or when an entry is unused; it runs with every build.
Icons
The UI never uses emoji. Every icon is the official VS Code Codicon artwork, inlined as SVG (src/icons.ts, generated by npm run icons:sync from the @vscode/codicons dev dependency) so it inherits currentColor and follows the active theme — tree items and commands use the matching $(icon) references in package.json.
Build
npm install
npm run compile
Package
npx @vscode/vsce package
Then code --install-extension pico-1.0.0.vsix or drag the .vsix into the VS Code Extensions view.
| |