You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Developer: Seif Hashish
Project: HashCortX
Summary:
138 commits since v2.0.0, which shipped in May and predates almost all of it.
The version moves in the three places that carry it — package.json, Cargo.toml
and tauri.conf.json — because a build that reports a version nobody cut is its
own small lie.
The changelog entry is the record of those commits, grouped by what a reader
needs rather than by commit order. Its first section is the largest, and it is
the honest shape of this release: features the app already advertised and had
never performed. Semantic search had never run in any shipped build. No export
had ever written a file. The Python sandbox hung on its first call and stayed
hung. 3D Forge could not start. The knowledge base never reached an ordinary
chat turn, and kept half of every document it was given. Every tool result was
cut to 800 characters, including the file the coding agent had just read.
It ends with what is still open, because a release that lists only its wins is
not much use to anyone deciding whether to install it: the build is unsigned,
Linux and Windows are compiled and tested but never run, ERP's repair path is
fixed and unexercised, the regenerate diff is unreadable over a table, and the
control sweep covers each mode from cold rather than in every state.
Stale claims corrected in the same pass, all of them re-measured rather than
carried over:
- The README described a release two versions behind and warned that `main` was
ahead of it. It also carried line counts from June (~30,600 JS, ~1,820 Rust;
measured now at ~35,700 and ~4,460), a test count of 34 against 89, a check
count of 72 against 1,376, and "around 7 MB" for an application that is 80 MB
installed — 33 MB of it the embedding model and most of the rest the runtime
that executes it. The interface source is 2.5 MB, which is the number that
claim was reaching for.
- It described "the ten-workspace structure". There are eight.
- ARCHITECTURE.md stated 1,190 checks and said nothing drives the UI. Both were
true when written; the second is what `npm run sweep` was built to stop being
true.
- SECURITY.md named v2.0.0 as the unsigned build.
The banner in docs/assets/ embeds the real mark as a data URI rather than
redrawing it, so it renders in release notes where a relative path would not
resolve. No hero image was added to the README; that is deliberate and unchanged.
Verification:
- npm run check — 1,376 passed, 0 failed. cargo test — 89 passed.
- `npm run tauri build` produced HashCortx_2.5.0_aarch64.dmg, 43 MB, and the
size and architecture claims above are read off that artefact rather than
estimated.
- Every number in the tables was measured today: JS and Rust line counts, test
and check counts, installed size, model size, interface source size.
@@ -8,26 +8,200 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
8
8
9
9
## [Unreleased]
10
10
11
-
Everything below has landed on `main` but is not yet in a tagged release or a DMG.
11
+
Nothing yet. See the open items at the end of 2.5.0 for what is known and not
12
+
finished.
13
+
14
+
---
15
+
16
+
## [2.5.0] — 2026-08-17
17
+
18
+
138 commits since 2.0.0. More stable and more capable than that release in every
19
+
area, and honest about what is still open — the list at the end is part of the
20
+
release, not an omission from it.
21
+
22
+
The theme of this release is **features that looked like they worked and did
23
+
not.** Most of what follows is not new functionality; it is functionality the app
24
+
already advertised, now actually happening. Where something was never reachable
25
+
in any shipped build, it says so.
26
+
27
+
### Things the app claimed to do and never did
28
+
29
+
-**Semantic search over your knowledge base had never run in any shipped
30
+
build.** The embedding model was imported from a CDN, which then fetched
31
+
weights from a host the content policy does not allow, and every call threw
32
+
into an empty catch. **bge-small-en-v1.5 (MIT, BAAI) is now compiled into the
33
+
binary** and runs natively in Rust — around a millisecond per passage.
34
+
Retrieval fuses keyword and vector rankings by position (Reciprocal Rank
35
+
Fusion) rather than comparing two scores that share no scale.
36
+
-**Every export in the app wrote nothing.** Seventeen download links and the
37
+
Python sandbox's file writer. A download is a capability the host has to opt
38
+
into, and this one never did, so the webview cancelled each one outright —
39
+
raising no error, which is why every button looked like it worked. Saving now
40
+
goes through the native dialog and a checked write.
41
+
-**The Python sandbox hung the agent for ever.** Its runtime fetch was refused
42
+
by the content policy, and the loader then neither resolved nor rejected, so
43
+
the first call hung and every later call awaited the same dead promise. It
44
+
runs in about three seconds now and produces real `.docx`, `.xlsx` and `.pdf`
45
+
files — the five pure-Python wheels are vendored rather than fetched.
46
+
-**3D Forge could not start.** three.js ships as two files and only one was
47
+
vendored; the asset server answered the missing one with the app's own HTML,
48
+
so the failure arrived as a misleading MIME error naming no file. glTF import
49
+
and export were dead for the same reason.
50
+
-**The knowledge base never reached an ordinary chat turn.** Retrieval sat
51
+
behind a condition that was always false, so the app reported injection as on
52
+
and retrieved nothing. It worked in the preview pane, which is why the store
53
+
itself always looked healthy.
54
+
-**Adding a document to the knowledge base kept half of it.** The reader
55
+
advanced 1,200 characters and stored 600.
56
+
-**Every tool result was cut to 800 characters** — including the file the
57
+
coding agent had just asked to read. This was the single largest reason the
58
+
agent felt weak.
59
+
-**Coder's shell had been broken for two weeks.** Argument names are renamed
60
+
across the Rust/JavaScript bridge, and three calls used the Rust spelling;
61
+
required arguments meant the call was rejected outright. The agent could read
62
+
and patch but never run anything.
63
+
-**Every call to Gemini with tools failed**, because the tools were handed over
64
+
in another provider's shape. Failing over *to* Gemini could never work either.
65
+
-**Every image was labelled JPEG** in all four provider hand-offs. Anthropic
66
+
validates that, so every screenshot sent to Claude — from chat as well — was
67
+
refused, and read as a provider problem.
68
+
-**Coder's Reject button did nothing.** The file was written before the row
69
+
appeared, and Reject only relabelled itself. It is Keep / Undo now, backed by
70
+
real content captured before the change.
71
+
-**ERP never finished building.** Three modes sent an OpenAI-shaped body to
72
+
Anthropic, which fails every call, and the failover then walked the whole
73
+
provider list twice with no deadline.
74
+
-**The Export menu opened off the screen**, because an ancestor with a filter
75
+
becomes the containing block for a fixed-position child. Once visible, its
76
+
items still called nothing: the function behind them threw on a loader used as
77
+
a getter, inside a promise nobody awaited.
78
+
- Web search, PubMed search and Google search each called a host the content
79
+
policy did not grant.
80
+
81
+
### Security
82
+
83
+
Every item here was a boundary that looked enforced and was not. Full detail in
84
+
[SECURITY.md](SECURITY.md).
85
+
86
+
-**The shell never checked the command text against protected paths** — only the
87
+
working directory. Reading a private key through `cat` succeeded while the
88
+
file tool refused the identical path.
89
+
-**A command naming a credential *directory* was allowed** — only spellings with
90
+
a filename after them were refused, so an archive or a copy of a whole key
91
+
store went through.
92
+
-**Reads anywhere on disk were auto-approved with no dialog.** Reads are free
93
+
inside the project and asked about outside it now.
94
+
-**The project boundary was a string comparison**, and a symlink is spelled
95
+
exactly like a folder, so a link inside the project pointing anywhere on disk
96
+
read as inside it. It is judged by where the path leads, resolved in Rust.
97
+
-**The recursive file tools followed links out of the project**, and one of them
98
+
returns file contents, through a search that raises no dialog.
99
+
-**A shell command's working directory was neither properly checked nor shown**,
100
+
though it decides what every relative path in the command means.
101
+
-**A model's reply could reach the network before anyone read it**: a markdown
102
+
image became a request the moment the message was drawn. Remote images render
103
+
as links, and the policy no longer permits a remote image host at all.
104
+
-**A move was approved once, for both paths joined into one string**, so a move
105
+
out of the project read as a move within it. One request per real path now.
106
+
-**A session grant for one address covered every address**, because a path
107
+
function was used on a URL.
108
+
- Web pages are fetched **in Rust**, over the connection that was checked —
109
+
resolve, refuse anything not public, pin the connection to that address, then
110
+
re-check every redirect by hand. This closes a resolve-then-refetch gap the
111
+
old documentation described as a known limit.
112
+
- Command runs are bounded: a five-minute deadline, no inherited input, and a
113
+
cap on captured output.
114
+
- The developer's own machine came out of the product — a LAN address that
115
+
shipped as a built-in preset, and a client that posted every knowledge chunk
116
+
to a server on it.
117
+
- Four registered native commands had no caller and are gone, including one that
118
+
would have written a secret back into the Keychain.
12
119
13
120
### Added
14
-
- Token usage log. Every model response appends one JSON line — timestamp, model id, token counts, and nothing else — to `~/.hashcortx/usage.jsonl`, so [HashMeterAi](https://github.com/Hash-7777/HashMeterAi) can report HashCortx usage as measured rather than estimated. Counts come from the provider's response metadata; when a provider reports none, nothing is written.
15
-
- Hash ecosystem section in the README and in the app's About pane.
16
-
- Seven hand-drawn SVG diagrams in `docs/assets/`, and a rebuilt README.
17
121
18
-
### Changed
19
-
-**API keys moved out of the macOS Keychain** into a plain-text JSON bundle (`hc_api_bundle_v2`) in the app's own local store, keyed by bundle identifier. A Keychain item's access list is bound to the binary's code signature, so every unsigned rebuild re-prompted for every key. Existing Keychain keys migrate across once on first run, then the Keychain entry is deleted. This is weaker than Keychain storage and is documented as such in [docs/SECURITY.md](docs/SECURITY.md). It will be reverted once the build is signed.
122
+
-**An offline knowledge base**: import documents, and the agent retrieves from
123
+
them locally. Nothing is sent anywhere to make it work.
124
+
-**Undo that outlives a restart.** Content captured before a change is written
125
+
inside the denylisted directory, so the agent cannot erase its own undo
126
+
history.
127
+
-**The coding agent reads PDFs, looks at images, and runs Python** that produces
128
+
real documents.
129
+
-**Chat reads a link you paste**, with or without an agent selected. It used to
130
+
answer from the address alone and invent the page.
131
+
-**A page is read in windows** rather than its first three paragraphs — measured
132
+
on real documentation, 68% of the text where it used to show 14% and say
133
+
nothing about the rest.
134
+
-**The memory map places facts by what they mean**, using the same bundled
135
+
model, with a second view that groups by key name. It states which layout is
136
+
live and how much of the difference between the facts a flat picture keeps.
137
+
-**A token usage log** at `~/.hashcortx/usage.jsonl` — timestamp, model id and
138
+
counts, nothing else — so [HashMeterAi](https://github.com/Hash-7777/HashMeterAi)
139
+
reports measured usage rather than an estimate.
140
+
-**A finished run lights up [Hash D Island](https://github.com/Hash-7777/Hash-D-Island)**
141
+
if it is installed. Metadata only.
142
+
-**The agent is told which machine it is on**, so it stops suggesting macOS
143
+
tools on Windows and Linux.
144
+
-**Windows and Linux support.** The shell is chosen in Rust rather than
145
+
hardcoded, and the path denylist understands Windows paths in both slash
146
+
directions. CI compiles and tests on all three systems.
20
147
21
-
### Fixed
22
-
-`docs/SECURITY.md` claimed keys were stored in the OS Keychain and that the JavaScript layer never sees a raw key. Both were the opposite of what the code does. It also documented a shell command allowlist, a prompt-injection filter, a Hardened Runtime and request rate limiting — none of which exist. Rewritten against the source.
23
-
-`docs/ARCHITECTURE.md` described a `core/` directory, `ai.rs`, `allowlist.rs` and a CI workflow that were never written. Replaced with the real tree.
24
-
-`docs/BRAND.md` specified a cyan primary that was never shipped, and described the brand mark as a `#`. The mark is the white brain; the colour situation is now documented honestly, including the three competing palettes.
25
-
-`CONTRIBUTING.md` required contributors to store keys via `keychain.rs` and forbade localStorage, contradicting the shipping code.
26
-
- README listed ten cloud providers (there are eleven — NVIDIA NIM was missing), eleven modes (there are ten workspace tabs), nine agent names that did not match `BUILTIN_AGENTS`, and one keyboard shortcut out of three. The Pyodide Python sandbox was undocumented.
27
-
- README screenshots sat under the wrong headings — the Coder section showed Agent Swarm, the Agent Swarm section showed the About pane, and Finance and 3D Forge were swapped.
28
-
-`scripts/gen-icon.py` draws a neon-green burst that is not the shipped icon. Flagged as legacy so nobody regenerates the wrong mark.
148
+
### Changed
29
149
30
-
---
150
+
-**Coder is rebuilt around the run**: files left, run centre, saved chats right,
151
+
panels that can be moved, hidden and remembered, and a real diff.
152
+
-**Settings is rebuilt around a section rail**, with a local-model walkthrough
153
+
whose steps check themselves against the machine.
154
+
-**Chat is rebuilt around the message**, and agents are a choice inside a chat
155
+
rather than a workspace of their own.
156
+
-**One visual identity.** Surfaces, lines, spacing, control heights, radii and
157
+
the colours that carry meaning live in one file; a mode declares its accent and
158
+
nothing else. Thirteen corner radii became five.
159
+
-**The app icon** fills its tile — the mark stood at about 65% of the height and
160
+
now stands at 82% — with rounded corners and a neon edge. It is generated by a
161
+
script from the artwork, so it is reproducible.
162
+
-**The structure was pulled apart**: `app.js` from 8,682 lines to 7,054, each
163
+
mode into its own folder with its own markup and stylesheet, the settings panes,
164
+
the memory store, the knowledge base and the map into files of their own.
165
+
- API keys are stored in the app's own local directory, not the OS Keychain. A
166
+
Keychain item is bound to the binary's signature, so every unsigned rebuild
167
+
re-prompted for every key. This is **weaker than Keychain storage** and
168
+
documented as such; it goes back once the build is signed.
169
+
170
+
### Verification
171
+
172
+
-**1,376 source checks** where there were none, each loading the real code
173
+
rather than a copy of it. **89 Rust tests**, up from 2.
174
+
-**A check that refuses a call to a name that does not exist.** One had been
175
+
called twice in the app and defined nowhere, throwing silently and taking the
176
+
next statement with it.
177
+
-**A sweep that clicks every control in every mode** in a real browser and
178
+
reports what throws — `npm run sweep`. All seven modes are clean from a cold
179
+
start.
180
+
- Checks that hold the pieces nothing else can see: that the content policy and
181
+
the code agree about every host, that every element a script looks up exists,
182
+
that no control exists which nothing touches, that hardcoded colours only ever
183
+
decrease, and that the bridge between the shell and the modes carries only what
184
+
is used.
185
+
- A pre-commit hook that refuses secrets, private addresses and local notes.
186
+
187
+
### Still open
188
+
189
+
Stated because a release that lists only its wins is not much use.
190
+
191
+
-**The build is unsigned and un-notarised.** Gatekeeper will refuse it on first
192
+
open; the steps are in the README and they are not optional.
193
+
-**Linux and Windows are compiled and tested, not run.** CI proves they build
194
+
and the tests pass. Nobody has opened the app on either.
195
+
-**ERP's repair path is fixed but unexercised.** Reaching it needs real provider
196
+
keys and a live rate limit.
197
+
-**The regenerate diff is unreadable when a reply contains a table**, because it
198
+
compares raw markdown.
199
+
-**The control sweep covers each mode from a cold start**, not states that need
200
+
content — a generated ERP system, a run in flight, a model loaded in Forge.
201
+
-**`styles.css` is a second design system**, 1,425 lines in its own namespace,
202
+
loaded last. It no longer collides with the shared tokens, and it has not been
203
+
merged away.
204
+
- 3D Forge has not been confirmed on a real machine since three.js was vendored.
@@ -41,14 +41,13 @@ Every AI request goes straight from your machine to the provider whose key you e
41
41
|**Type**| Native desktop app (Tauri v2) |
42
42
|**Runs on**| macOS Apple Silicon — built and used daily. Linux and Windows compile and pass their tests in CI, but nobody has run the app there yet |
43
43
|**License**| MIT |
44
-
|**Latest release**| v2.0.0 (May 2026), 8 MB |
45
-
|**Current `main`**| 41.2 MB — 7 MB app, 34 MB bundled embedding model. Not yet released |
44
+
|**Latest release**| v2.5.0 (17 August 2026) — 43 MB DMG for Apple Silicon, 80 MB installed. 33 MB of that is the bundled embedding model, and most of the rest is the runtime that executes it |
> **`main` is ahead of the release.** v2.0.0 predates the offline knowledge base, the security fixes and the cross-platform work described below. Build from source if you want what is written here.
50
+
> **v2.5.0 is what this page describes.**It carries 138 commits since v2.0.0 — the offline knowledge base, the security work, Windows and Linux support, and a long list of features that were advertised and did not run. [What changed](CHANGELOG.md#250--2026-08-17), including what is still open.
52
51
53
52
---
54
53
@@ -121,7 +120,9 @@ Results are ranked by meaning and by keyword at once, then fused — so a rare e
121
120
122
121
## Install
123
122
124
-
Download the DMG from the [latest release](https://github.com/Hash-7777/HashCortX/releases/latest), open it, drag HashCortx to `/Applications`. That release is v2.0.0 and predates the work described above — build from source for that.
123
+
Download the DMG from the [latest release](https://github.com/Hash-7777/HashCortX/releases/latest), open it, drag HashCortx to `/Applications`.
124
+
125
+
The DMG is built for **Apple Silicon**. On an Intel Mac, build from source.
125
126
126
127
The build is unsigned and not notarised, so on first launch right-click the app and choose **Open**, then **Open** again. If macOS still refuses:
127
128
@@ -147,7 +148,7 @@ Before pushing, run what CI runs:
147
148
148
149
```bash
149
150
npm run check # scripts parse, guard, retrieval, agent context
150
-
cargo test --manifest-path src-tauri/Cargo.toml #34 tests
151
+
cargo test --manifest-path src-tauri/Cargo.toml #89 tests
|**Python**| Pyodide (CPython on WebAssembly) with pandas, numpy, matplotlib, python-docx, openpyxl, reportlab |
167
168
|**Vendored libs**| marked, highlight.js, DOMPurify, mermaid, pdf.js, jsPDF, three.js — all local, no CDN |
168
169
169
-
No bundler is a deliberate constraint. It keeps the application itself around 7 MB and lets any reader follow a feature from the button that triggers it to the Rust function that performs it, without a source map.
170
+
No bundler is a deliberate constraint. The interface is about 2.5 MB of source that ships as written, so any reader can follow a feature from the button that triggers it to the Rust function that performs it, without a source map. What makes the download large is the embedding model and the runtime that executes it, not the app.
@@ -220,7 +221,7 @@ Best effort as of August 2026. If something is out of date, [open an issue](http
220
221
221
222
**Are my API keys encrypted?** No — see above.
222
223
223
-
**Was it built with AI?** Yes, heavily. Roughly 30 million tokens across Claude, GPT and other frontier models during the v2.0.0 build, under human architecture, review and correction. Disclosed because HashCortx is itself an AI tool, and hiding that would be incoherent. Every product decision — the ten-workspace structure, the local-first rule, the Permission Guard, the swarm failover pattern, the source-grounding constraints — is the author's.
224
+
**Was it built with AI?** Yes, heavily. Roughly 30 million tokens across Claude, GPT and other frontier models during the v2.0.0 build, under human architecture, review and correction. Disclosed because HashCortx is itself an AI tool, and hiding that would be incoherent. Every product decision — the workspace structure, the local-first rule, the Permission Guard, the swarm failover pattern, the source-grounding constraints — is the author's.
224
225
225
226
More at [Wiki → FAQ](https://github.com/Hash-7777/HashCortX/wiki/FAQ).
0 commit comments