Skip to content

Releases: ThinkWatchProject/ThinkWatch-Core

ThinkWatch Core 0.56.0

Choose a tag to compare

@github-actions github-actions released this 29 Sep 16:31
f09d002

This release keeps a conversation on the upstream that holds its prompt cache and decides a turn's route once, moves a request to the next upstream when a stream fails before its first content, sets an upstream aside for as long as the reason it gives calls for, answers token counts that no upstream can serve with a local estimate, and resends a request whose reasoning another account sealed.

Upgrade notes

  • The control-plane protocol version (CONTROL_API_VERSION) is now 30. ThinkWatch Lite connects only to a core with the same protocol version, and has to regenerate its protocol types from this release to use it. ThinkWatch Lite 2026.9.24 includes 0.55.2 (protocol 28) and does not connect to 0.56.0: a server used with it stays on 0.55.2 until the app is updated to a release that includes 0.56.0. sudo twcore upgrade --version 0.55.2 --restart switches a server back to 0.55.2.
  • The request store's schema is unchanged (22): the request history is kept.
  • groups[].session_affinity is removed. A configuration that still sets it (only session_affinity: false was ever written) is refused; delete the line.
  • Changed in the protocol:
    • Removed: GroupView.session_affinity, GroupView.hurts_cache, GroupInput.session_affinity, DryRunResult.hurts_cache.
    • RequestRouted.affinity and RoutingView.affinity (AffinityView, Stay): whether the request kept its turn's route and why it stayed with the upstream that answered before.
    • Overview.failover (FailoverView).
    • AttemptOutcome has estimated.
  • New in the configuration: the failover section (see Setting a failing upstream aside).
  • Message codes: new config.failover_range and gw.upstream.stream_opening_error; removed gw.count_tokens.bedrock_model.

A conversation stays where its cache is. Routing rules used to be evaluated for every request, and only load-balance groups kept a session on one upstream. A rule on input_tokens or on images could therefore switch upstreams in the middle of an agent's turn, and a failover moved the conversation away from the upstream holding its prompt cache for good.

  • A conversation is recognised by the client's session header (x-claude-code-session-id, session_id, conversation_id and a few others) together with the content fingerprint, or by the fingerprint alone. A turn lasts from a user message until the next one; tool results belong to the turn.
  • The routing decision made at the start of a turn (rule, group, rewrites) holds for the rest of the turn. It is made again when the input approaches the smallest context window among the candidate models, where the price data gives one.
  • The next request goes first to the upstream that last answered the conversation, including one that took over after a failover: always within a turn, and across turns while its last answer read or wrote at least 1024 cached tokens less than five minutes ago. An upstream that is set aside, not among the candidates or in another group is not held to.
  • load-balance takes turns between new conversations only. session_affinity and the warnings that a group lowers the cache hit rate are gone, since no strategy drops a warm cache in the middle of a conversation any more.

Errors at the start of a stream fail over. An upstream can answer 200, open a stream and report an error as its first event: Anthropic's overloaded_error, the Codex backend's response.failed when the usage limit is reached, Bedrock's throttlingException, an error chunk from a Chat or Gemini upstream. The client had received nothing yet, and the error still reached it. A streamed answer is now held until its first content arrives, and an error before that point moves the request to the next candidate, as an error status does. What was read while waiting is passed on unchanged. The wait ends after failover.stream_start_wait_secs (15) or 1 MiB; the last candidate is not held.

Setting a failing upstream aside. Failures are sorted by the reason the upstream gives.

  • 401, 403, 402 and 404 now move the request to the next candidate. A 400 or 422 does so only when its body names an insufficient balance, a used-up quota or an unavailable model; other 4xx still go to the client unchanged. The last candidate's own 4xx reaches the client as the upstream wrote it.
  • An insufficient balance sets the upstream aside for no_balance_pause_secs (1800). A used-up quota sets it aside until the reset time the upstream names in the body, in its quota headers or in a GLM 429, and for quota_pause_secs (3600) when it names none. A rate limit with Retry-After (or Gemini's retryDelay) sets it aside for that long, at most rate_limit_max_pause_secs (3600). A missing model moves on without counting against the upstream.
  • Failures without a stated reason pause the upstream after failures_to_pause (3) in a row, for pause_secs (60), doubling with each further pause up to max_pause_secs (600) and starting over after a success.
  • A request with a single candidate is never affected, and when every candidate is set aside they are all tried.

Counting tokens. /v1/messages/count_tokens and Gemini's :countTokens routed to an upstream of another format, or to a same-format upstream that answers 404 or 405, are answered by the gateway with an estimate of the system prompt, messages, tool calls and results, and tool definitions; nothing is sent to that upstream. The answer carries x-thinkwatch-local: 1, and the request is recorded as a local answer with no cost. A count does not fail over to another format or another model. Counting through an AWS Bedrock upstream still answers 501 not_supported, after which Claude Code counts precisely itself.

Reasoning sealed by another account. Reasoning items carry content encrypted or signed for the account that produced them. After a failover from one account to another, the upstream refuses them (Responses' invalid_encrypted_content, Anthropic's invalid signature in a thinking block). The request is now sent once more without them, and the refused items are left out up front on the conversation's later turns to that upstream.

Downloads

Platform Binary Archive for server installation
Linux, x86_64 twcore-x86_64-unknown-linux-gnu twcore-x86_64-unknown-linux-gnu.tar.gz
Linux, aarch64 twcore-aarch64-unknown-linux-gnu twcore-aarch64-unknown-linux-gnu.tar.gz
macOS, Apple silicon twcore-aarch64-apple-darwin —
Windows, x64 twcore-x86_64-pc-windows-msvc.exe —
Windows, ARM64 twcore-aarch64-pc-windows-msvc.exe —

Each file is published with a .sha256 file beside it. A Linux archive contains twcore, the systemd unit twcore.service and LICENSE. ThinkWatch Lite includes its own copy of twcore; the files here are for running core separately, such as on a server.

Server installation

On Linux (x86_64 or aarch64), the install script sets up twcore as a systemd service. This installs 0.56.0:

curl -fsSL https://raw.githubusercontent.com/ThinkWatchProject/ThinkWatch-Core/main/scripts/install.sh | sudo sh -s -- --version 0.56.0

An installation made with the script switches to 0.56.0 with:

sudo twcore upgrade --version 0.56.0 --restart

Configuration, the remote control port and connecting ThinkWatch Lite are described in docs/server.md.

Verifying a download

A .sha256 file holds the SHA-256 of the file followed by its name. With both files in the current directory, on Linux:

sha256sum -c twcore-x86_64-unknown-linux-gnu.tar.gz.sha256

On macOS:

shasum -a 256 -c twcore-aarch64-apple-darwin.sha256

On Windows, in PowerShell, the following prints True when the binary matches:

(Get-FileHash .\twcore-x86_64-pc-windows-msvc.exe).Hash -eq (Get-Content .\twcore-x86_64-pc-windows-msvc.exe.sha256).Split()[0]

The install script and twcore upgrade check the SHA-256 themselves.

What's Changed

  • Keep a conversation on the upstream that answered it, and hold a turn's route by @fylorn in #237
  • Estimate count_tokens locally; resend without reasoning sealed by another account by @fylorn in #238
  • Fail over on errors at the start of a stream; pause upstreams by the reason they give by @fylorn in #239
  • chore: v0.56.0 by @fylorn in #240

Full Changelog: v0.55.2...v0.56.0

ThinkWatch Core 0.55.2

Choose a tag to compare

@github-actions github-actions released this 29 Sep 06:32
75d5ef2

This release stops a Bedrock API key that is not valid from passing the connection check.

Upgrade notes

  • The control-plane protocol version is unchanged (28) and so is the request store's schema (22). ThinkWatch Lite 2026.9.23 includes 0.54.0 (protocol 27) and does not connect to 0.55.x: a server used with it stays on 0.54.0 until the app is updated to a release that includes 0.55.2.
  • No message codes change.

Checking a Bedrock upstream. AWS answers a Bedrock API key that is not valid with AccessDeniedException ("Authentication failed: …", "Invalid API Key format: …"), the same exception it uses for a valid credential that may not list models. The check took every AccessDeniedException on the model listing to mean the credential works, so a mistyped key passed with "The credential works, and it has no permission to list models", and the background model fetch said the same. Only a refusal whose message says the identity is not authorized, which is how IAM denies an action, now counts as missing list permission; any other one reports the key as rejected. AWS's message is only inspected and never passed on, since it names the account.

Downloads

Platform Binary Archive for server installation
Linux, x86_64 twcore-x86_64-unknown-linux-gnu twcore-x86_64-unknown-linux-gnu.tar.gz
Linux, aarch64 twcore-aarch64-unknown-linux-gnu twcore-aarch64-unknown-linux-gnu.tar.gz
macOS, Apple silicon twcore-aarch64-apple-darwin —
Windows, x64 twcore-x86_64-pc-windows-msvc.exe —
Windows, ARM64 twcore-aarch64-pc-windows-msvc.exe —

Each file is published with a .sha256 file beside it. A Linux archive contains twcore, the systemd unit twcore.service and LICENSE. ThinkWatch Lite includes its own copy of twcore; the files here are for running core separately, such as on a server.

Server installation

On Linux (x86_64 or aarch64), the install script sets up twcore as a systemd service. This installs 0.55.2:

curl -fsSL https://raw.githubusercontent.com/ThinkWatchProject/ThinkWatch-Core/main/scripts/install.sh | sudo sh -s -- --version 0.55.2

An installation made with the script switches to 0.55.2 with:

sudo twcore upgrade --version 0.55.2 --restart

Configuration, the remote control port and connecting ThinkWatch Lite are described in docs/server.md.

Verifying a download

A .sha256 file holds the SHA-256 of the file followed by its name. With both files in the current directory, on Linux:

sha256sum -c twcore-x86_64-unknown-linux-gnu.tar.gz.sha256

On macOS:

shasum -a 256 -c twcore-aarch64-apple-darwin.sha256

On Windows, in PowerShell, the following prints True when the binary matches:

(Get-FileHash .\twcore-x86_64-pc-windows-msvc.exe).Hash -eq (Get-Content .\twcore-x86_64-pc-windows-msvc.exe.sha256).Split()[0]

The install script and twcore upgrade check the SHA-256 themselves.

What's Changed

  • fix(gateway): report a Bedrock API key that is not valid as rejected by @fylorn in #235
  • chore: v0.55.2 by @fylorn in #236

Full Changelog: v0.55.1...v0.55.2

ThinkWatch Core 0.55.1

Choose a tag to compare

@github-actions github-actions released this 29 Sep 05:27
548fec0

This release stops a request that requires a server-side tool, such as Claude Code's web search, from being sent without it to an upstream of another format.

Upgrade notes

  • The control-plane protocol version is unchanged (28) and so is the request store's schema (22). ThinkWatch Lite 2026.9.23 includes 0.54.0 (protocol 27) and does not connect to 0.55.x: a server used with it stays on 0.54.0 until the app is updated to a release that includes 0.55.1.
  • New message codes: gw.convert.tool_unsendable and gw.convert.tools_unsendable.

Requests that require a server-side tool. Claude Code runs each web search as a request that carries only the server-side web_search tool and forces the model to use it. Converted for an upstream of another format (AWS Bedrock, OpenAI, Gemini), the server tool was dropped, since only the provider it belongs to runs it: the model answered without searching, and Claude Code passed that answer on as the search results. When the tool a request forces cannot be sent in the upstream's format, that attempt is no longer made. The next upstream of the route is tried, and if none can take the request the client gets a 400 that names the tool and the upstream. Server-side tools offered alongside other tools, which the model is free to leave unused, are still dropped and listed in the request's details as before.

Downloads

Platform Binary Archive for server installation
Linux, x86_64 twcore-x86_64-unknown-linux-gnu twcore-x86_64-unknown-linux-gnu.tar.gz
Linux, aarch64 twcore-aarch64-unknown-linux-gnu twcore-aarch64-unknown-linux-gnu.tar.gz
macOS, Apple silicon twcore-aarch64-apple-darwin —
Windows, x64 twcore-x86_64-pc-windows-msvc.exe —
Windows, ARM64 twcore-aarch64-pc-windows-msvc.exe —

Each file is published with a .sha256 file beside it. A Linux archive contains twcore, the systemd unit twcore.service and LICENSE. ThinkWatch Lite includes its own copy of twcore; the files here are for running core separately, such as on a server.

Server installation

On Linux (x86_64 or aarch64), the install script sets up twcore as a systemd service. This installs 0.55.1:

curl -fsSL https://raw.githubusercontent.com/ThinkWatchProject/ThinkWatch-Core/main/scripts/install.sh | sudo sh -s -- --version 0.55.1

An installation made with the script switches to 0.55.1 with:

sudo twcore upgrade --version 0.55.1 --restart

Configuration, the remote control port and connecting ThinkWatch Lite are described in docs/server.md.

Verifying a download

A .sha256 file holds the SHA-256 of the file followed by its name. With both files in the current directory, on Linux:

sha256sum -c twcore-x86_64-unknown-linux-gnu.tar.gz.sha256

On macOS:

shasum -a 256 -c twcore-aarch64-apple-darwin.sha256

On Windows, in PowerShell, the following prints True when the binary matches:

(Get-FileHash .\twcore-x86_64-pc-windows-msvc.exe).Hash -eq (Get-Content .\twcore-x86_64-pc-windows-msvc.exe.sha256).Split()[0]

The install script and twcore upgrade check the SHA-256 themselves.

What's Changed

  • fix(gateway): refuse a hop that would drop the tool a request requires by @fylorn in #233
  • chore: v0.55.1 by @fylorn in #234

Full Changelog: v0.55.0...v0.55.1

ThinkWatch Core 0.55.0

Choose a tag to compare

@github-actions github-actions released this 29 Sep 01:56
5d3db23

This release adds AWS Bedrock upstreams. Requests to them are converted to Converse and signed per request, and prompt-cache breakpoints and Claude's thinking now survive that conversion. Each request is priced by the model it was actually sent as, long-context prices follow the thresholds the price data gives, and an error an upstream reports partway through a stream now counts as a failure.

Upgrade notes

  • The control-plane protocol version (CONTROL_API_VERSION) is now 28. ThinkWatch Lite connects only to a core with the same protocol version, and has to regenerate its protocol types from this release to use it. ThinkWatch Lite 2026.9.23 includes 0.54.0 (protocol 27) and does not connect to 0.55.0: a server used with it stays on 0.54.0 until the app is updated to a release that includes 0.55.0. sudo twcore upgrade --version 0.54.0 --restart switches a server back to 0.54.0.
  • The request store's schema is unchanged (22): the request history is kept.
  • Changed in the protocol:
    • Protocol has bedrock.
    • ProviderInput.aws and ProviderView.aws (AwsKeys): the access keys, or the name of an AWS profile, and the region to sign for.
    • ProviderView.region and ProviderPreview.region: the region of a Bedrock upstream.
    • AttemptView.model: the model an attempt sent when a routing rule rewrote it.
  • New in the configuration: the protocol bedrock and providers[].aws. The 200K long-context threshold of a price sheet's input_above_200k and output_above_200k now counts cache reads and writes (see Priced by the model that was sent).
  • New message codes:
    • config.credential.: bedrock_oauth, key_and_aws, bedrock_no_credential, aws_not_bedrock, aws_empty, aws_profile_and_keys, aws_empty_profile, aws_signed_header, aws_no_region, aws_bad_region, aws_region_mismatch
    • config.aws_profile.: no_home, unreadable, not_found, unsupported, no_keys
    • gw.upstream.: aws_token_expired, aws_profile_expired, bedrock_refused, bedrock_refused_unnamed, sign_failed, eventstream_broken, stream_exception, stream_error
    • gw.probe.aws_token_expired, gw.probe.bedrock_list_denied, gw.count_tokens.bedrock_model, gw.count_tokens.bedrock_upstream, control.replay_bedrock, l3.sign_failed

AWS Bedrock upstreams. An upstream at https://bedrock-runtime.<region>.amazonaws.com is recognized as bedrock. It authenticates in one of three ways:

  • A Bedrock API key in key, sent as Authorization: Bearer.
  • AWS access keys in aws: access_key_id, secret_access_key and, for temporary credentials, session_token, each of which can be ${VAR}. Every request is signed with them (SigV4) once its body is final.
  • aws.profile: the access keys of a profile in the AWS credential files (~/.aws/credentials, ~/.aws/config, or the files AWS_SHARED_CREDENTIALS_FILE and AWS_CONFIG_FILE name) on the machine core runs on. The files are read again when they change, so a tool that refreshes temporary keys there needs no restart. Nothing is run to obtain a credential: a profile that signs in through IAM Identity Center, runs a credential_process or assumes a role is refused, naming the setting.

Requests in every client format are converted to Converse and ConverseStream. The binary eventstream is turned into server-sent events as it arrives, so usage, the first token, output redaction and tool-call inspection work as they do for any other upstream. The anthropic-beta values Bedrock accepts for Claude are carried into the request body. The model list comes from the region's control plane: the foundation models that can be invoked on demand, the inference profiles AWS defines (us.anthropic.claude-…, global.…), and the account's application inference profiles, listed by the ARN they are invoked by. Checking the connection and the inference speed test go through the same signing. For a VPC endpoint or a proxy, write its address in base_url and the region in aws.region.

  • AWS's text for a refused credential (HTTP 401 or 403) names the account and the IAM identity. The client receives the gateway's own sentence instead, and AWS's text is not recorded as the request's error.
  • An expired session token is named as such; for a profile, the message says to refresh the profile.
  • An exception AWS sends inside a stream ends the request as a failure.
  • count_tokens for a model that only Bedrock upstreams serve is answered with 501 not_supported, the answer Claude Code's guidance for gateways names; Claude Code then counts with a one-token request. Bedrock's own CountTokens covers only some older Claude models on bedrock-runtime.
  • A replay to a Bedrock upstream is refused: a replay sends the recorded request as it was, and Bedrock takes only the Converse format, which no client sends.

The code that speaks to Bedrock (signing, the eventstream, the endpoints and the model catalog) is the new layer-one crate tw-bedrock, which ThinkWatch Enterprise shares.

Converse keeps cache breakpoints and thinking. The conversion to Converse used to drop cache_control, so a client that cached its prompt never hit the cache through Bedrock. Cache breakpoints now become cachePoint blocks (at most four, as Bedrock allows), with the one-hour TTL where the client asked for it, and cache reads and writes, one-hour writes included, are read back. Claude's thinking and effort are sent in additionalModelRequestFields, and its reasoning comes back as reasoning content.

Priced by the model that was sent. A routing rule can send a request as another model, and the upstream charges for the model it received. Each attempt now records the model it sent when a rule rewrote it (AttemptView.model), and a request is priced by the model of the attempt that served it. The row still names the model the client asked for. The list of unpriced models names the model a price has to be set for.

  • A Bedrock model the price data does not list borrows a price, always marked estimated: an inference profile from the model it is named after, and an Anthropic model on Bedrock from Anthropic's own name for it.
  • Long-context tiers are read with the threshold the price data gives (200K for Claude Sonnet 4 and 4.5, 272K for GPT-5.4 and later), including their cache prices. A request's input counts its cache reads and writes when the tier is chosen. The 272K tier was not recognized before, and a request with a warm cache was priced as a short one.
  • A price the data does not give is filled in, and the cost is marked estimated whenever it is used: a one-hour cache write costs twice the input price (it used to fall back to the five-minute price), and the missing cache prices of a long-context tier grow with its input price.

Errors partway through a stream. An upstream can answer 200, stream part of an answer and then report an error in the stream: Anthropic's overloaded_error, Responses' response.failed, an error in a Chat or Gemini frame. Such a request was recorded as finished; it is now a failure, with the usage the upstream reported before the error.

Listed models. GET /v1/models and GET /v1/models/:model no longer stamp each model with the time of the request. created and created_at are now the Unix epoch, since the gateway does not know when a model was released.

Downloads

Platform Binary Archive for server installation
Linux, x86_64 twcore-x86_64-unknown-linux-gnu twcore-x86_64-unknown-linux-gnu.tar.gz
Linux, aarch64 twcore-aarch64-unknown-linux-gnu twcore-aarch64-unknown-linux-gnu.tar.gz
macOS, Apple silicon twcore-aarch64-apple-darwin —
Windows, x64 twcore-x86_64-pc-windows-msvc.exe —
Windows, ARM64 twcore-aarch64-pc-windows-msvc.exe —

Each file is published with a .sha256 file beside it. A Linux archive contains twcore, the systemd unit twcore.service and LICENSE. ThinkWatch Lite includes its own copy of twcore; the files here are for running core separately, such as on a server.

Server installation

On Linux (x86_64 or aarch64), the install script sets up twcore as a systemd service. This installs 0.55.0:

curl -fsSL https://raw.githubusercontent.com/ThinkWatchProject/ThinkWatch-Core/main/scripts/install.sh | sudo sh -s -- --version 0.55.0

An installation made with the script switches to 0.55.0 with:

sudo twcore upgrade --version 0.55.0 --restart

Configuration, the remote control port and connecting ThinkWatch Lite are described in docs/server.md.

Verifying a download

A .sha256 file holds the SHA-256 of the file followed by its name. With both files in the current directory, on Linux:

sha256sum -c twcore-x86_64-unknown-linux-gnu.tar.gz.sha256

On macOS:

shasum -a 256 -c twcore-aarch64-apple-darwin.sha256

On Windows, in PowerShell, the following prints True when the binary matches:

(Get-FileHash .\twcore-x86_64-pc-windows-msvc.exe).Hash -eq (Get-Content .\twcore-x86_64-pc-windows-msvc.exe.sha2...
Read more

ThinkWatch Core 0.54.0

Choose a tag to compare

@github-actions github-actions released this 27 Sep 17:40
3f68ecf

This release records when each response's first token arrives and how fast the response is generated, and corrects the generation rate that GET /live reports.

Upgrade notes

  • The control-plane protocol version (CONTROL_API_VERSION) is now 27. ThinkWatch Lite connects only to a core with the same protocol version, and has to regenerate its protocol types from this release to use it. ThinkWatch Lite 2026.9.21 includes 0.53.0 (protocol 26) and does not connect to 0.54.0: a server used with it stays on 0.53.0 until the app is updated to a release that includes 0.54.0. sudo twcore upgrade --version 0.53.0 --restart switches a server back to 0.53.0.
  • The format of the request history changed (request store schema 22, from 21). On its first start, 0.54.0 replaces the request history and the stored request and response bodies of an earlier version with an empty store; the configuration is kept. Switching back to an earlier version empties it again.
  • Changed in the protocol: the new event RequestFirstToken { id, ttft_ms }, RequestFinished.tokens_per_sec, HistoryRow.ttft_ms and HistoryRow.tokens_per_sec, and the new endpoints GET /token-rate and GET /token-rate/provider, which return TokenRateView { model, p50, samples }. GET /latency and GET /latency/provider now report the time to the first token. No message code changed.

First token. The headers of a streamed response usually come back as soon as the upstream receives the request. The upstream then queues the request and reads the prompt before it produces anything, and the time a user waits is the time to the first token, not to the headers. The gateway now reads each successful streamed response in the upstream's format and reports the moment the first text, reasoning or tool call arrives; opening frames such as message_start and response.created do not count. A response that is not streamed arrives whole and has no first token. GET /latency and GET /latency/provider now give percentiles of this time, so responses that are not streamed are left out of them. url-test groups still pick the upstream with the fastest response headers.

Generation speed. Each finished streamed request has a generation speed: the output produced after the first token, divided by the time from the first token to the end.

  • When the model reasoned before the first token without streaming its reasoning, those reasoning tokens were generated outside that time. They are subtracted when the upstream reports how many there were, as OpenAI and Gemini do. When it does not, as with Anthropic, the request has no speed rather than one several times too high.
  • Reasoning that is streamed as it happens is counted.
  • Responses that are not streamed, cancelled and failed requests, and generations shorter than half a second have no speed.

GET /token-rate and GET /token-rate/provider give the median speed by model and by upstream, with the number of samples.

The live rate. GET /live used to divide each request's output by the time after its response headers. A response that is not streamed gets its headers only when generation is done, so that time was a few milliseconds, and one such request could push the rate to tens of thousands of tokens per second. The rate now combines the speeds of the requests that have one, weighted by their generation time.

Downloads

Platform Binary Archive for server installation
Linux, x86_64 twcore-x86_64-unknown-linux-gnu twcore-x86_64-unknown-linux-gnu.tar.gz
Linux, aarch64 twcore-aarch64-unknown-linux-gnu twcore-aarch64-unknown-linux-gnu.tar.gz
macOS, Apple silicon twcore-aarch64-apple-darwin —
Windows, x64 twcore-x86_64-pc-windows-msvc.exe —
Windows, ARM64 twcore-aarch64-pc-windows-msvc.exe —

Each file is published with a .sha256 file beside it. A Linux archive contains twcore, the systemd unit twcore.service and LICENSE. ThinkWatch Lite includes its own copy of twcore; the files here are for running core separately, such as on a server.

Server installation

On Linux (x86_64 or aarch64), the install script sets up twcore as a systemd service. This installs 0.54.0:

curl -fsSL https://raw.githubusercontent.com/ThinkWatchProject/ThinkWatch-Core/main/scripts/install.sh | sudo sh -s -- --version 0.54.0

An installation made with the script switches to 0.54.0 with:

sudo twcore upgrade --version 0.54.0 --restart

Configuration, the remote control port and connecting ThinkWatch Lite are described in docs/server.md.

Verifying a download

A .sha256 file holds the SHA-256 of the file followed by its name. With both files in the current directory, on Linux:

sha256sum -c twcore-x86_64-unknown-linux-gnu.tar.gz.sha256

On macOS:

shasum -a 256 -c twcore-aarch64-apple-darwin.sha256

On Windows, in PowerShell, the following prints True when the binary matches:

(Get-FileHash .\twcore-x86_64-pc-windows-msvc.exe).Hash -eq (Get-Content .\twcore-x86_64-pc-windows-msvc.exe.sha256).Split()[0]

The install script and twcore upgrade check the SHA-256 themselves.

What's Changed

  • Record when the first token arrives and how fast a response is generated by @fylorn in #220
  • chore: v0.54.0 by @fylorn in #221

Full Changelog: v0.53.0...v0.54.0

ThinkWatch Core 0.53.0

Choose a tag to compare

@github-actions github-actions released this 27 Sep 15:09
9b4b2f7

This release changes what ThinkWatch sends to upstreams. Each upstream now receives the request and only the headers it needs; the client's own identity stays with ThinkWatch unless an upstream asks for it. It also fixes two problems with ChatGPT account upstreams.

Upgrade notes

  • The control-plane protocol version is now 26 (it was 25). The request store's schema is unchanged (21). ThinkWatch Lite 2026.9.20 includes 0.52.1 (protocol 25) and does not connect to 0.53.0, so a server used with it stays on 0.52.x until the app is updated to a release that includes 0.53.0.
  • Upstreams now see ThinkWatch's User-Agent instead of the client's. An upstream that admits only certain clients, such as Kimi For Coding, Bailian Coding Plan or a relay restricted to official clients, needs the new provider field forward_client_identity: true.
  • New message code: config.credential.chatgpt_client_identity.

Each upstream gets only what it needs. Client request headers used to reach the upstream almost unchanged. Only credentials, a few transport headers and, when a request was translated, the client format's own protocol headers were removed. Claude Code's User-Agent, x-app, x-stainless-* and session ID, Gemini CLI's installation ID and a browser client's Cookie and Origin all went through. Outbound headers now come from three sources only:

  • Set by ThinkWatch: its own User-Agent, and content-type when the body was translated.
  • The upstream's configuration: the credential and the headers written there. OpenAI-Organization and OpenAI-Project belong here, because they belong to the upstream's key.
  • The client's request, only for the headers the upstream's protocol uses:
    • Anthropic: anthropic-*, except anthropic-dangerous-direct-browser-access.
    • OpenAI: Idempotency-Key and X-Client-Request-Id.
    • Gemini: none.
    • Every protocol: content-type and accept when the body passes through unchanged.

An Anthropic request without anthropic-version now gets the default one. When the body passes through unchanged, identity fields that clients fill in themselves are removed from it: Claude Code's metadata.user_id, and the Codex installation ID and turn metadata in client_metadata.

forward_client_identity. With this field on, an upstream also receives the client's own User-Agent, x-app, originator, version, session_id and x-codex-* headers, and the body's identity fields are kept. These are the client's own values; nothing is made up. The field is off by default. A ChatGPT account upstream refuses it: that upstream always names ThinkWatch as the sender.

ChatGPT account upstreams.

  • New models were missing from the list. The Codex backend leaves a model out of the list when its minimum client version is above the client_version that the caller reports. ThinkWatch reported 0.0.0, so a model such as gpt-6-luna, which needs Codex 0.155.0, was not listed, and requests for it were refused with "No upstream serves model …" even though the account can use it. ThinkWatch now reports 99999.0.0, so the list shows every model the account can use. Requests still name ThinkWatch as their origin.
  • The ChatGPT app's identity is no longer forwarded. The Codex inside the ChatGPT desktop app adds an attestation generated by the app (x-oai-attestation), its installation ID and turn metadata. ThinkWatch forwarded them together with the token it had obtained itself, and on one account OpenAI revoked that token within seconds of the first such request.
    • From the client, the Codex backend now receives only x-codex-turn-state, x-openai-internal-codex-responses-lite and x-codex-beta-features.
    • The attestation, installation ID and turn metadata cannot be set in an upstream's configured headers.
  • Request bodies are compressed. Requests to the Codex backend are compressed with zstd, which is what Codex does when it talks to that backend itself.

Downloads

Platform Binary Archive for server installation
Linux, x86_64 twcore-x86_64-unknown-linux-gnu twcore-x86_64-unknown-linux-gnu.tar.gz
Linux, aarch64 twcore-aarch64-unknown-linux-gnu twcore-aarch64-unknown-linux-gnu.tar.gz
macOS, Apple silicon twcore-aarch64-apple-darwin —
Windows, x64 twcore-x86_64-pc-windows-msvc.exe —
Windows, ARM64 twcore-aarch64-pc-windows-msvc.exe —

Each file is published with a .sha256 file beside it. A Linux archive contains twcore, the systemd unit twcore.service and LICENSE. ThinkWatch Lite includes its own copy of twcore; the files here are for running core separately, such as on a server.

Server installation

On Linux (x86_64 or aarch64), the install script sets up twcore as a systemd service. This installs 0.53.0:

curl -fsSL https://raw.githubusercontent.com/ThinkWatchProject/ThinkWatch-Core/main/scripts/install.sh | sudo sh -s -- --version 0.53.0

An installation made with the script switches to 0.53.0 with:

sudo twcore upgrade --version 0.53.0 --restart

Configuration, the remote control port and connecting ThinkWatch Lite are described in docs/server.md.

Verifying a download

A .sha256 file holds the SHA-256 of the file followed by its name. With both files in the current directory, on Linux:

sha256sum -c twcore-x86_64-unknown-linux-gnu.tar.gz.sha256

On macOS:

shasum -a 256 -c twcore-aarch64-apple-darwin.sha256

On Windows, in PowerShell, the following prints True when the binary matches:

(Get-FileHash .\twcore-x86_64-pc-windows-msvc.exe).Hash -eq (Get-Content .\twcore-x86_64-pc-windows-msvc.exe.sha256).Split()[0]

The install script and twcore upgrade check the SHA-256 themselves.

What's Changed

  • fix(gateway): list every model a ChatGPT account can use; stop forwarding the ChatGPT app's identity by @fylorn in #217
  • feat(gateway): send each upstream only what it needs by @fylorn in #218
  • chore: v0.53.0 by @fylorn in #219

Full Changelog: v0.52.1...v0.53.0

ThinkWatch Core 0.52.1

Choose a tag to compare

@github-actions github-actions released this 26 Sep 15:38
cd8baef

This release fixes two routing problems: a routing rule that rewrites the model was judged by the model the client asked for, and requests in the OpenAI Responses and Gemini formats were never recognized as part of a conversation.

Upgrade notes

  • The control-plane protocol version is unchanged (25) and so is the request store's schema (21). ThinkWatch Lite 2026.9.18 includes 0.51.0 (protocol 24) and does not connect to 0.52.x: a server used with it stays on 0.51.0 until the app is updated to a release that includes 0.52.1.
  • New message codes: gw.model.no_upstream_rewritten and gw.model.not_allowed_rewritten.

Rewriting the model. A rule that sets the model, for example to send the Claude-style names that Claude Desktop requires to a GLM or DeepSeek upstream, was refused with "No upstream serves model …" whenever the target upstream lists its models. Admission, skipping the candidates that cannot serve a request, and the cheapest group's price comparison all looked at the model the client wrote, before any rule rewrote it. They now look at the model each upstream will actually be asked for, including a rewrite that applies to one upstream only (provider_would_be), so admission runs after the rules have decided. When a rewritten model is not served, the error names both models. The routing dry run judges the candidates the same way.

Conversations in the Responses and Gemini formats. Requests from Codex and other clients that use the OpenAI Responses or Gemini format were never assigned to a session, because the fingerprint read only the Anthropic and Chat Completions fields. A load-balancing group with session affinity, which is the default, sent all of them to its first upstream, and the traffic view did not group them into sessions. The fingerprint now also reads instructions and input, and systemInstruction and contents, and uses the request's prompt_cache_key when it has one. Codex sends one per conversation, and Codex conversations started in the same repository open with identical text.

Downloads

Platform Binary Archive for server installation
Linux, x86_64 twcore-x86_64-unknown-linux-gnu twcore-x86_64-unknown-linux-gnu.tar.gz
Linux, aarch64 twcore-aarch64-unknown-linux-gnu twcore-aarch64-unknown-linux-gnu.tar.gz
macOS, Apple silicon twcore-aarch64-apple-darwin —
Windows, x64 twcore-x86_64-pc-windows-msvc.exe —
Windows, ARM64 twcore-aarch64-pc-windows-msvc.exe —

Each file is published with a .sha256 file beside it. A Linux archive contains twcore, the systemd unit twcore.service and LICENSE. ThinkWatch Lite includes its own copy of twcore; the files here are for running core separately, such as on a server.

Server installation

On Linux (x86_64 or aarch64), the install script sets up twcore as a systemd service. This installs 0.52.1:

curl -fsSL https://raw.githubusercontent.com/ThinkWatchProject/ThinkWatch-Core/main/scripts/install.sh | sudo sh -s -- --version 0.52.1

An installation made with the script switches to 0.52.1 with:

sudo twcore upgrade --version 0.52.1 --restart

Configuration, the remote control port and connecting ThinkWatch Lite are described in docs/server.md.

Verifying a download

A .sha256 file holds the SHA-256 of the file followed by its name. With both files in the current directory, on Linux:

sha256sum -c twcore-x86_64-unknown-linux-gnu.tar.gz.sha256

On macOS:

shasum -a 256 -c twcore-aarch64-apple-darwin.sha256

On Windows, in PowerShell, the following prints True when the binary matches:

(Get-FileHash .\twcore-x86_64-pc-windows-msvc.exe).Hash -eq (Get-Content .\twcore-x86_64-pc-windows-msvc.exe.sha256).Split()[0]

The install script and twcore upgrade check the SHA-256 themselves.

What's Changed

  • fix(gateway): judge a rewritten model by the name it sends; tell Codex and Gemini conversations apart by @fylorn in #215
  • chore: v0.52.1 by @fylorn in #216

Full Changelog: v0.52.0...v0.52.1

ThinkWatch Core 0.52.0

Choose a tag to compare

@github-actions github-actions released this 26 Sep 12:30
2b06824

This release hands ThinkWatch Lite the upstream and proxy settings as they are written in the configuration, so its edit dialogs can show them, and stops repeating the version segment when an upstream's base URL ends with it.

Upgrade notes

  • The control-plane protocol version (CONTROL_API_VERSION) is now 25. ThinkWatch Lite connects only to a core with the same protocol version, and has to regenerate its protocol types from this release to use it. ThinkWatch Lite 2026.9.18 includes 0.51.0 (protocol 24) and does not connect to 0.52.0: a server used with it stays on 0.51.0 until the app is updated to a release that includes 0.52.0. sudo twcore upgrade --version 0.51.0 --restart switches a server back to 0.51.0.
  • The request store's schema is unchanged (21). Upgrading from 0.50.x or 0.51.0 keeps the request history.
  • Changed in the protocol: ProviderView.base_url, ProviderView.key (now a string), HeaderView.value, the new OAuthView.refresh and OAuthView.client_secret, and ProxyView.auth (which replaces has_auth) carry the settings as written; base_url_masked, SecretView and HeaderView.masked are gone. ProviderInput.base_url is required, ProviderInput.key is an optional string and every HeaderInput has a value; ProxyInput.auth is optional. SecretChange and ProxyAuthInput are gone, and so is the message code control.pass_has_expansion.

Settings as written. The upstream and proxy views used to mask what they showed. The base URL was cut down to its origin, so https://bedrock-mantle.us-east-1.api.aws/v1 was shown without /v1, with a note that credentials had been hidden when there were none. API keys and header values were masked, and OAuth refresh tokens, client secrets and proxy credentials were left out. The app could not fill its edit dialogs in, and every save carried "keep what is saved" states instead of values. The views now carry the settings as they are written in config.yaml, and a save carries the whole definition. The access token of an OAuth credential stays out of the view, and an OAuth credential can still be kept as it is on save: while a dialog is open the gateway may renew the token and write back a new refresh token. GET /config already returned the file unmasked. Diagnostics bundles and logs still mask.

Proxy passwords from the environment. A proxy password may be a ${NAME} reference, as the configuration reference shows (pass: ${PROXY_PASSWORD}). A password containing ${ used to be refused.

Base URLs that end with a version segment. A base URL written up to its version segment, as provider docs give it (https://api.openai.com/v1) and as the configuration reference says, got every request and every connection check sent to .../v1/v1/...: the client's path (/v1/chat/completions) was appended as it was. When the base URL's path ends with the version segment the request path starts with (v1, v2, v1beta, ...), that segment is now used once. Other segments are joined as before.

Downloads

Platform Binary Archive for server installation
Linux, x86_64 twcore-x86_64-unknown-linux-gnu twcore-x86_64-unknown-linux-gnu.tar.gz
Linux, aarch64 twcore-aarch64-unknown-linux-gnu twcore-aarch64-unknown-linux-gnu.tar.gz
macOS, Apple silicon twcore-aarch64-apple-darwin —
Windows, x64 twcore-x86_64-pc-windows-msvc.exe —
Windows, ARM64 twcore-aarch64-pc-windows-msvc.exe —

Each file is published with a .sha256 file beside it. A Linux archive contains twcore, the systemd unit twcore.service and LICENSE. ThinkWatch Lite includes its own copy of twcore; the files here are for running core separately, such as on a server.

Server installation

On Linux (x86_64 or aarch64), the install script sets up twcore as a systemd service. This installs 0.52.0:

curl -fsSL https://raw.githubusercontent.com/ThinkWatchProject/ThinkWatch-Core/main/scripts/install.sh | sudo sh -s -- --version 0.52.0

An installation made with the script switches to 0.52.0 with:

sudo twcore upgrade --version 0.52.0 --restart

Configuration, the remote control port and connecting ThinkWatch Lite are described in docs/server.md.

Verifying a download

A .sha256 file holds the SHA-256 of the file followed by its name. With both files in the current directory, on Linux:

sha256sum -c twcore-x86_64-unknown-linux-gnu.tar.gz.sha256

On macOS:

shasum -a 256 -c twcore-aarch64-apple-darwin.sha256

On Windows, in PowerShell, the following prints True when the binary matches:

(Get-FileHash .\twcore-x86_64-pc-windows-msvc.exe).Hash -eq (Get-Content .\twcore-x86_64-pc-windows-msvc.exe.sha256).Split()[0]

The install script and twcore upgrade check the SHA-256 themselves.

What's Changed

  • fix(forward): don't repeat the version segment a base URL ends with by @fylorn in #212
  • feat(control): hand the UI upstream and proxy settings as written by @fylorn in #213
  • chore: v0.52.0 by @fylorn in #214

Full Changelog: v0.51.0...v0.52.0

ThinkWatch Core 0.51.0

Choose a tag to compare

@github-actions github-actions released this 26 Sep 07:33
f620c77

This release stops counting the MCP tool calls of the older GLM Coding Plans as a quota, marks only the weekly window when a model request gets business code 1310, and tells the app at once when a GLM key turns out to have no plan.

Upgrade notes

  • The control-plane protocol version (CONTROL_API_VERSION) is now 24. ThinkWatch Lite connects only to a core with the same protocol version, and has to regenerate its protocol types from this release to use it. ThinkWatch Lite 2026.9.17 includes 0.49.0 (protocol 22) and no released version of the app includes 0.50.0, so a server used with the app stays on 0.49.x until the app is updated to a release that includes 0.51.0. sudo twcore upgrade --version 0.49.1 --restart switches a server back to 0.49.1.
  • The request store's schema is unchanged (21). Upgrading from 0.50.0 keeps the request history. Upgrading from 0.49.x or earlier replaces the request history and the stored bodies with an empty store on the first start, as 0.50.0 does; the configuration is kept. Switching back to 0.49.x empties it again.
  • Changed in the protocol: the quota window monthly is gone, and a QuotaSeen with empty windows means the upstream's quota was taken down. No endpoint, type or message code changed.

MCP calls are not a quota. The quota endpoint of the older GLM Coding Plans also reports a count (TIME_LIMIT) of calls to Z.ai's own MCP tools: search-prime, web-reader and zread. Those calls do not go through the gateway, so the count says nothing about the requests it forwards. Core no longer reads it: there is no monthly window, and a used-up count no longer marks the upstream used up or emits QuotaExhausted. credits are reported only for the windows of credit-based plans (CREDIT_LIMIT).

1310 is the weekly quota. A 429 with business code 1310 on a model request marks the weekly window used up, whatever its message says. 1308 still marks the 5-hour window. For 1316 to 1321 the window still comes from the message when it names the 5-hour or weekly window; otherwise it is the fuller of the two known windows, or the weekly one when neither is known.

A key without a plan. When a GLM key is found to have no plan, core clears the quota it had stored for that upstream and emits a QuotaSeen with empty windows, so the app removes the quota at once instead of on its next read of /quota.

Downloads

Platform Binary Archive for server installation
Linux, x86_64 twcore-x86_64-unknown-linux-gnu twcore-x86_64-unknown-linux-gnu.tar.gz
Linux, aarch64 twcore-aarch64-unknown-linux-gnu twcore-aarch64-unknown-linux-gnu.tar.gz
macOS, Apple silicon twcore-aarch64-apple-darwin —
Windows, x64 twcore-x86_64-pc-windows-msvc.exe —
Windows, ARM64 twcore-aarch64-pc-windows-msvc.exe —

Each file is published with a .sha256 file beside it. A Linux archive contains twcore, the systemd unit twcore.service and LICENSE. ThinkWatch Lite includes its own copy of twcore; the files here are for running core separately, such as on a server.

Server installation

On Linux (x86_64 or aarch64), the install script sets up twcore as a systemd service. This installs 0.51.0:

curl -fsSL https://raw.githubusercontent.com/ThinkWatchProject/ThinkWatch-Core/main/scripts/install.sh | sudo sh -s -- --version 0.51.0

An installation made with the script switches to 0.51.0 with:

sudo twcore upgrade --version 0.51.0 --restart

Configuration, the remote control port and connecting ThinkWatch Lite are described in docs/server.md.

Verifying a download

A .sha256 file holds the SHA-256 of the file followed by its name. With both files in the current directory, on Linux:

sha256sum -c twcore-x86_64-unknown-linux-gnu.tar.gz.sha256

On macOS:

shasum -a 256 -c twcore-aarch64-apple-darwin.sha256

On Windows, in PowerShell, the following prints True when the binary matches:

(Get-FileHash .\twcore-x86_64-pc-windows-msvc.exe).Hash -eq (Get-Content .\twcore-x86_64-pc-windows-msvc.exe.sha256).Split()[0]

The install script and twcore upgrade check the SHA-256 themselves.

What's Changed

  • fix(quota): ignore GLM MCP call counts and announce a cleared quota by @fylorn in #210
  • chore: v0.51.0 by @fylorn in #211

Full Changelog: v0.50.0...v0.51.0

ThinkWatch Core 0.50.0

Choose a tag to compare

@github-actions github-actions released this 26 Sep 03:16
982cd87

This release lets Claude Desktop's third-party mode use the gateway, cleans the extensions DeepSeek Harness adds to its requests before they reach an upstream other than DeepSeek, reads the GLM Coding Plan quota of Z.ai and BigModel upstreams, and recognises requests from Antigravity CLI. A gateway bound to a network interface now starts even when that interface is not there yet.

Upgrade notes

  • The format of the request history changed (request store schema 21, from 20). On its first start, 0.50.0 replaces the request history and the stored request and response bodies of an earlier version with an empty store; the configuration is kept. Switching back to an earlier version empties it again.
  • The control-plane protocol version (CONTROL_API_VERSION) is now 23. ThinkWatch Lite connects only to a core with the same protocol version, and has to regenerate its protocol types from this release to use it. ThinkWatch Lite 2026.9.17 includes 0.49.0 (protocol 22) and does not connect to 0.50.0: a server used with it stays on 0.49.x until the app is updated to a release that includes 0.50.0. sudo twcore upgrade --version 0.49.1 --restart switches a server back to 0.49.1.
  • New in the protocol: QuotaWindow.credits (a new type, QuotaCredits { total, used, remaining }), the quota window monthly, and session_log_bytes on RequestStarted and HistoryRow. New message code: gw.files.unsupported.
  • /v1/files and /files now answer 404 on the gateway instead of being forwarded to an upstream.

Claude Desktop. Claude Desktop in third-party inference mode, and the Claude Code engine it embeds, expect a few things of a gateway:

  • HEAD /api/hello, the probe Desktop sends at startup, is answered with 200 by the gateway itself, without a key and without reaching an upstream. It used to be refused with 401.
  • The client gives up on a stream that is silent for about five minutes. When a client speaking Anthropic Messages has received nothing for 15 seconds, the gateway writes event: ping, so a converted upstream that is reasoning or queued at length no longer looks like a dead connection. The timer runs from the last bytes the client received, not from the upstream's, because conversion drops the upstream's own keep-alive comments. Pings go only between frames, are not recorded in the stored body or counted as output, and are never sent to clients of other formats. After ten minutes without a byte from the upstream the gateway stops pinging, so a half-open upstream connection ends on the client's timer instead of lasting forever.
  • /v1/models answers Anthropic clients in the Anthropic shape: type, display_name, created_at, has_more, first_id and last_id, and, for models whose id reads as Claude, anthropic_family_tier, which Desktop uses to resolve aliases such as sonnet. The OpenAI fields stay on the objects, because clients that send only x-api-key are also read as Anthropic.

DeepSeek Harness. DeepSeek Harness sends DeepSeek's extensions to whichever base URL it is given: top-level dsh_* fields, among them a session log of the whole conversation of up to 8 MiB per request, role: system entries in messages, tool_addition and tool_removal blocks with defer_loading tools, thinking enabled without a budget, and x-deepseek-harness-* headers. A request is recognised by its User-Agent or a dsh_* field. To DeepSeek's official endpoint it goes through unchanged. To any other upstream, every request from it, including count_tokens, has the dsh_* fields removed, its system entries appended to system in order, the tool change blocks and defer_loading removed and listed on the hop as a conversion lists what it drops, and a thinking without a budget rewritten to what the model accepts. The x-deepseek-harness-* headers are not forwarded, and the tool changes beta is taken out of anthropic-beta, with every line of a header sent on several lines kept. session_log_bytes gives the size of the session log a request carried, so the app can show that it carried one. /v1/files and /files answer 404: a file uploaded to the upstream picked at that moment cannot be used by a later request routed to another, and the 404 makes DeepSeek Harness send images inline.

GLM Coding Plan quota. An upstream whose base_url host is api.z.ai or open.bigmodel.cn is read as a GLM Coding Plan upstream. Its responses carry no quota headers, so GET /quota asks the account's quota endpoint for each enabled one that is due (at most once a minute, waiting up to 5 seconds), and traffic to one asks at most every 5 minutes; failures back off from 30 seconds to 5 minutes. Windows are 5h, weekly and monthly (the monthly MCP calls of the older plans), told apart by their length, and a reset time beyond a window's length is dropped. Credit-based plans report credits with the three numbers the endpoint gives. A 429 carrying a used-up quota code marks the window used up and emits QuotaExhausted. A key without a plan is left alone for an hour, and a key that had a quota needs two no-plan answers in a row before it is believed, because a transient server error returns the same code.

Antigravity CLI. Antigravity CLI sends the Go genai SDK's default user agent. A user agent that starts with google-genai-sdk and carries Google's internal Go toolchain (gl-go/ followed by cl/) is now reported as the client antigravity-cli. Programs built on the SDK with a public Go release are not.

Listening on an interface that is not there yet. When listen.gateway.bind names a network interface that does not exist or is offline, or an address that is not on this machine yet, twcore used to exit at startup. The gateway now listens on 127.0.0.1 only and says why in the listen status (gw.listen.no_such_nic, gw.listen.nic_offline), asks the system again every three seconds, adds the interface once it appears, moves to its new address when it changes, and drops back to loopback when it goes away. This lets the desktop app on Windows bind the gateway to the WSL adapter, which appears only once WSL has started and changes address on every restart. A loopback that cannot be bound is still fatal at startup.

Downloads

Platform Binary Archive for server installation
Linux, x86_64 twcore-x86_64-unknown-linux-gnu twcore-x86_64-unknown-linux-gnu.tar.gz
Linux, aarch64 twcore-aarch64-unknown-linux-gnu twcore-aarch64-unknown-linux-gnu.tar.gz
macOS, Apple silicon twcore-aarch64-apple-darwin —
Windows, x64 twcore-x86_64-pc-windows-msvc.exe —
Windows, ARM64 twcore-aarch64-pc-windows-msvc.exe —

Each file is published with a .sha256 file beside it. A Linux archive contains twcore, the systemd unit twcore.service and LICENSE. ThinkWatch Lite includes its own copy of twcore; the files here are for running core separately, such as on a server.

Server installation

On Linux (x86_64 or aarch64), the install script sets up twcore as a systemd service. This installs 0.50.0:

curl -fsSL https://raw.githubusercontent.com/ThinkWatchProject/ThinkWatch-Core/main/scripts/install.sh | sudo sh -s -- --version 0.50.0

An installation made with the script switches to 0.50.0 with:

sudo twcore upgrade --version 0.50.0 --restart

Configuration, the remote control port and connecting ThinkWatch Lite are described in docs/server.md.

Verifying a download

A .sha256 file holds the SHA-256 of the file followed by its name. With both files in the current directory, on Linux:

sha256sum -c twcore-x86_64-unknown-linux-gnu.tar.gz.sha256

On macOS:

shasum -a 256 -c twcore-aarch64-apple-darwin.sha256

On Windows, in PowerShell, the following prints True when the binary matches:

(Get-FileHash .\twcore-x86_64-pc-windows-msvc.exe).Hash -eq (Get-Content .\twcore-x86_64-pc-windows-msvc.exe.sha256).Split()[0]

The install script and twcore upgrade check the SHA-256 themselves.

What's Changed

  • feat(gateway): meet what Claude Desktop's third-party mode asks of a gateway by @fylorn in #203
  • feat(quota): read the GLM Coding Plan quota for Z.ai and BigModel upstreams by @fylorn in #204
  • feat(gateway): clean DeepSeek Harness requests for non-DeepSeek upstreams by @fylorn in #205
  • fix(gateway): start on loopback when the interface to listen on is not there yet by @fylorn in #206
  • feat(gateway): recognise Antigravity CLI requests as antigravity-cli by @fylorn in #207
  • fix: pre-release review fixes for pings, DeepSeek Harness cleaning and GLM quota by @fylorn in #208
  • chore: v0.50.0 by @fylorn in https://github.com/ThinkWatchProject/ThinkWatch-C...
Read more