Skip to content

Releases: titaniumcoder/pocket-cfo

v2.0.0

Choose a tag to compare

@titaniumcoder titaniumcoder released this 04 Sep 23:02

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 /info counts the stored chats and can delete them all. Present only when OPENAI_API_KEY is 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_user tool ends the turn with a question card — clickable options and, where sensible, a free-text field — and the answer resumes the turn.
  • read_data_file and write_data_file (MCP, GET/PUT /api/files/{name}, chat) serve budget.json, accounts.json and config.json whole, 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) and POST /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, -3 for 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_URL and OPENAI_EXTRA_BODY configure 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 to gpt-5 (openai/gpt-5 on OpenRouter) with a log line.
  • Release candidates: a tag such as v2.0.0-rc.1 publishes 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 :next while production stays on stable tags. The release-it skill cuts and later promotes them.

Changed

  • STATE_DIR is the one writable directory the app keeps between restarts — cache/ for Toggl, chat/ for the chats — set to /var/data/pocketcfo by the image, so a deployment mounts one volume there and sets nothing else. TOGGL_CACHE_DIR stays as an override, so an existing deployment keeps working; CHAT_DIR overrides the chat half.

v2.0.0-rc.4

v2.0.0-rc.4 Pre-release
Pre-release

Choose a tag to compare

@titaniumcoder titaniumcoder released this 04 Sep 21:28

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

v2.0.0-rc.3 Pre-release
Pre-release

Choose a tag to compare

@titaniumcoder titaniumcoder released this 04 Sep 20:40

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_file and write_data_file (MCP, GET/PUT /api/files/{name}, chat) serve budget.json, accounts.json and config.json whole, 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_user tool 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

v2.0.0-rc.2 Pre-release
Pre-release

Choose a tag to compare

@titaniumcoder titaniumcoder released this 04 Sep 18:22

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_DIR is the one writable directory the app keeps between restarts — cache/ for Toggl, chat/ for the chats — set to /var/data/pocketcfo by the image, so a deployment mounts one volume there and sets nothing else. TOGGL_CACHE_DIR and CHAT_DIR remain as overrides; chats no longer default to a subdirectory of the Toggl cache.

Fixed

  • OPENAI_API_KEY alone is enough to boot: an unset OPENAI_MODEL falls back to gpt-5 (openai/gpt-5 on 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

v2.0.0-rc.1 Pre-release
Pre-release

Choose a tag to compare

@titaniumcoder titaniumcoder released this 04 Sep 18:06

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_KEY is 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). /info counts the stored chats and can delete them all.
  • OPENAI_API_KEY, OPENAI_MODEL, OPENAI_BASE_URL, OPENAI_EXTRA_BODY and CHAT_DIR configure 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; /info shows the resolved values.
  • Release candidates: a tag such as v2.0.0-rc.1 publishes 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 :next while production stays on stable tags. The release-it skill cuts and later promotes them.
  • derive_transaction_ids (MCP) and POST /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, -3 for 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

Choose a tag to compare

@titaniumcoder titaniumcoder released this 04 Sep 15:05

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

Choose a tag to compare

@titaniumcoder titaniumcoder released this 03 Sep 20:05

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

Choose a tag to compare

@titaniumcoder titaniumcoder released this 03 Sep 19:34

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

Choose a tag to compare

@titaniumcoder titaniumcoder released this 03 Sep 19:24

Fixes to the cache statistics on /info.

Fixes

  • 1a27e4e the cache statistics on /info state the year in every timestamp
  • 0aed84c a remaining quota count without a reset header still counts
  • 66050b9 the quota row on /info appears only once Toggl has reported a quota; the header names of an API's first answer are logged once

v0.35.1

Choose a tag to compare

@titaniumcoder titaniumcoder released this 03 Sep 19:01

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.