Releases: titaniumcoder/pocket-cfo
Release list
v2.0.0
Previewed as 2.0.0-rc.1 to 2.0.0-rc.4. The feature that defines 2.0 is the in-app chat: reconciling bank statements in a conversation inside Pocket CFO, with every write staged for approval, instead of driving an external agent against the API.
Added
- A Chat tab, for admins only, where a bank statement is uploaded and reconciled in a conversation with a model behind any OpenAI-compatible endpoint. The conversation fills the screen with the composer pinned at the bottom — a full-width box, an Attach button with removable file chips, Enter to send — and the Changes rail sits beside it on a wide screen and below it on a phone. The transcript tells logs from answers: the model's reasoning, tool calls and results are gray, collapsed lines between your message and the answer, which is a white card with light formatting. Several chats per user, kept on the server so they survive a reload or a redeploy; a chat can be closed, and
/infocounts the stored chats and can delete them all. Present only whenOPENAI_API_KEYis set. - Every write the model proposes is staged, not committed: the Changes rail shows it as a pending change — a file edit as its diff — and you approve them together, one commit per touched file however many tool calls produced it, or discard one by one. Every applied change has a Revert button that commits the previous content back, or removes a file the change created.
- A turn runs on the server until it finishes: the page follows it over a live event stream and picks it up again after a reload or a tab switch, the composer is disabled meanwhile, and the completion is streamed from the provider so a reasoning model may take as long as it needs — only an endpoint that sends nothing for three minutes is given up on.
- The chat asks instead of assuming: an
ask_usertool ends the turn with a question card — clickable options and, where sensible, a free-text field — and the answer resumes the turn. read_data_fileandwrite_data_file(MCP,GET/PUT /api/files/{name}, chat) servebudget.json,accounts.jsonandconfig.jsonwhole, for what the narrower tools cannot express — a moved dividend, a new category or account, a new dated rule. A write must pass the file's own validation, becomes one commit with the reason as its message, and reports the diff.derive_transaction_ids(MCP) andPOST /api/actuals/ids(REST) hand an agent the stable id of every statement line — a short hash of account, date, amount and description, suffixed-2,-3for identical lines in one call — so ids are computed by the app rather than by the agent, and a re-imported statement still dedups line for line.OPENAI_API_KEY,OPENAI_MODEL,OPENAI_BASE_URLandOPENAI_EXTRA_BODYconfigure the chat: any OpenAI-compatible endpoint, the model passed through verbatim (an OpenRouter preset works), and a JSON object merged into every request for provider-specific fields such as OpenRouter's zero-data-retention routing. The key alone is enough to boot: an unset model falls back togpt-5(openai/gpt-5on OpenRouter) with a log line.- Release candidates: a tag such as
v2.0.0-rc.1publishes the image under its own tag and:next— never:latest— is marked pre-release on GitHub, and does not notify the data repo, so a test deployment can follow:nextwhile production stays on stable tags. Therelease-itskill cuts and later promotes them.
Changed
STATE_DIRis the one writable directory the app keeps between restarts —cache/for Toggl,chat/for the chats — set to/var/data/pocketcfoby the image, so a deployment mounts one volume there and sets nothing else.TOGGL_CACHE_DIRstays as an override, so an existing deployment keeps working;CHAT_DIRoverrides the chat half.
v2.0.0-rc.4
The fourth candidate for 2.0: rc.3 lost long answers to a request deadline. Published as :next, not :latest.
Fixed
- The chat no longer fails with "reaching the model endpoint: error reading response body: context deadline exceeded" on a long answer: the completion is streamed from the provider and assembled as it arrives, so a reasoning model may take as long as it needs; only an endpoint that sends nothing for three minutes is given up on, and a turn has nine minutes per model call in total.
v2.0.0-rc.3
The third candidate for 2.0: the chat becomes usable — laid out for the job, turns that survive a tab switch, questions instead of guesses, and the three hand-maintained files editable with a diff to approve. Published as :next, not :latest.
Added
read_data_fileandwrite_data_file(MCP,GET/PUT /api/files/{name}, chat) servebudget.json,accounts.jsonandconfig.jsonwhole, for what the narrower tools cannot express — a moved dividend, a new category or account, a new dated rule. A write must pass the file's own validation, becomes one commit with the reason as its message, and reports the diff; in the chat it is staged and reviewed as that diff.- The chat asks instead of assuming: an
ask_usertool ends the turn with a question card — clickable options and, where sensible, a free-text field — and the answer resumes the turn. The system prompt makes this the normal way to resolve an unknown account, category or line.
Changed
- The chat page is laid out for the job: the conversation fills the screen with the composer pinned at the bottom — a full-width box, an Attach button with removable file chips, Enter to send — and the Changes rail sits beside it on a wide screen and below it on a phone.
- The chat transcript tells logs from answers: the model's reasoning, its tool calls and their results are gray, collapsed monospace lines between your message and the answer, and the answer is a white card with light formatting (lists, bold, code), everything wrapped.
Fixed
- A chat turn no longer dies with the browser tab: it runs on the server until it finishes, the page follows it over a live event stream and picks it up again after a reload or a tab switch, and the composer is disabled while it runs.
v2.0.0-rc.2
The second candidate for 2.0: rc.1 refused to boot on a deployment that carried OPENAI_API_KEY without the rest of the chat configuration. Published as :next, not :latest.
Changed
STATE_DIRis the one writable directory the app keeps between restarts —cache/for Toggl,chat/for the chats — set to/var/data/pocketcfoby the image, so a deployment mounts one volume there and sets nothing else.TOGGL_CACHE_DIRandCHAT_DIRremain as overrides; chats no longer default to a subdirectory of the Toggl cache.
Fixed
OPENAI_API_KEYalone is enough to boot: an unsetOPENAI_MODELfalls back togpt-5(openai/gpt-5on OpenRouter) and an unset chat directory falls back to a temporary one, each with a log line — 2.0.0-rc.1 refused to start in both cases, which would have crashed a deploy that already carried the key.
v2.0.0-rc.1
A release candidate for 2.0: the in-app chat. Published as :next, not :latest.
Added
- A Chat tab, for admins only, where a bank statement is uploaded and reconciled in a conversation with a model: read tools run at once, every write the model proposes is staged as a pending change that nothing commits, and the conversation is kept on the server so it survives a reload or a redeploy. Several chats per user; a chat can be closed. Present only when
OPENAI_API_KEYis set. Pending changes are approved together — one commit per touched file, however many tool calls produced it — or discarded one by one, and every applied change has a Revert button that commits the previous content back (or removes a file the change created)./infocounts the stored chats and can delete them all. OPENAI_API_KEY,OPENAI_MODEL,OPENAI_BASE_URL,OPENAI_EXTRA_BODYandCHAT_DIRconfigure the in-app Chat tab: any OpenAI-compatible endpoint, the model passed through verbatim, and a directory for the chats. The key set without a model or without anywhere to keep chats refuses to boot;/infoshows the resolved values.- Release candidates: a tag such as
v2.0.0-rc.1publishes the image under its own tag and:next— never:latest— is marked pre-release on GitHub, and does not notify the data repo, so a test deployment can follow:nextwhile production stays on stable tags. Therelease-itskill cuts and later promotes them. derive_transaction_ids(MCP) andPOST /api/actuals/ids(REST) hand an agent the stable id of every statement line — a short hash of account, date, amount and description, suffixed-2,-3for identical lines in one call — so ids are computed by the app rather than by the agent, and a re-imported statement still dedups line for line.
v1.0.1
Fixed
- The year view's Income row no longer claims a shifted period such as "March 2026 – February 2027". A year's income is January to December of that year; only the month pages say which month their income funds.
v1.0.0
The first stable release. Nothing changes in the application beyond the two points below;
1.0.0 marks the switch to strict semantic versioning: from here a breaking change bumps the
major version.
Added
- This changelog, covering every release since 0.1.0.
Removed
- The per-endpoint header log lines introduced in 0.35.3. They established that neither Toggl API sends quota headers; the client still reads them should they ever appear.
v0.35.3
Endpoint-level header diagnostics in the log.
Fixes
- fecf7b3 the log notes the first answer of every Toggl endpoint with its status, header names, and any quota, rate-limit, retry or service-level header values, to find out whether any call states the hourly quota
v0.35.2
Fixes to the cache statistics on /info.
Fixes
v0.35.1
Versioned cache directory.
- a3792c6 the Toggl cache directory carries a VERSION marker; a release whose cache format differs deletes the old cache files there (top-level .json files only) on its first start and begins afresh. Deployments upgrading from v0.34.0 or v0.35.0 with TOGGL_CACHE_DIR set pull the year once more on this first start.