Skip to content

v2.0.0

Latest

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.