I promised myself I'd build ClarkCant in public, and building in public means showing the messy middle, not only the launch screenshot. So here it is: what actually changed over the last two weeks, read straight from the git history, and what is still not done.

Some context first. The repository's first commit is from 16 September 2026. As of 5 October it holds 685 commits. That sounds like a lot for under three weeks, and it is. 150 of those commits carry a co-author line for Claude, an AI coding agent, which is a bit funny given everything I complain about in my minimalism essay. I don't think that makes the number impressive on its own. Commits are not features. What matters is whether a normal person using Clark feels any of it, so that's how I'll walk through it.

Counts computed with git log on the ClarkCant main branch for 22 September 2026 00:00 to 5 October 2026 in Asia/Saigon time. 358 commits, merge commits excluded. Of those, 135 carry the feat type and 114 the fix type in their conventional-commit prefix; the rest are docs, test, refactor, ci, chore and perf. 166 distinct pull request numbers appear at the end of commit subjects in that window. The whole history from the first commit on 16 September 2026 holds 685 commits, 64 of them merges.

Underlying data
[
  {
    "id": "commits",
    "label": "Commits, merges excluded",
    "value": 358
  },
  {
    "id": "feat",
    "label": "feat commits",
    "value": 135
  },
  {
    "id": "fix",
    "label": "fix commits",
    "value": 114
  },
  {
    "id": "prs",
    "label": "Pull request numbers referenced",
    "value": 166
  },
  {
    "id": "total",
    "label": "All commits since 16 September",
    "value": 685
  }
]
Counted from git log on the main branch, 22 September 00:00 to 5 October 2026, Asia/Saigon time.

Donut of the 358 non-merge commits from 22 September to 5 October 2026 by conventional-commit prefix: feat 135, fix 114, docs 63, test 25, refactor 14, and 7 others (ci 3, chore 2, perf 1, build 1).

Underlying data
[
  {
    "label": "feat",
    "commits": 135
  },
  {
    "label": "fix",
    "commits": 114
  },
  {
    "label": "docs",
    "commits": 63
  },
  {
    "label": "test",
    "commits": 25
  },
  {
    "label": "refactor",
    "commits": 14
  },
  {
    "label": "ci, chore, perf, build",
    "commits": 7
  }
]

One thing the numbers say honestly: there are almost as many fix commits as feat commits. A lot of these two weeks was not adding things but making things tell the truth, behave the same on Windows, or stop being drawn in the wrong place. I'm fine with that ratio. That's what finishing looks like.

The rhythm isn't steady either. The first three days of the window hold over 200 commits, then four days are almost silent, then it picks up again. Building in public means showing the quiet days too.

Bar chart of non-merge commits per day in Asia/Saigon time: Sep 22: 87, Sep 23: 57, Sep 24: 62, Sep 25: 2, Sep 26: 0, Sep 27: 1, Sep 28: 5, Sep 29: 34, Sep 30: 46, Oct 1: 6, Oct 2: 15, Oct 3: 15, Oct 4: 17, Oct 5: 11. Total 358. The first three days (22 to 24 September) hold 206 commits; 25 to 28 September were nearly silent.

Underlying data
[
  {
    "name": "Sep 22",
    "commits": 87
  },
  {
    "name": "Sep 23",
    "commits": 57
  },
  {
    "name": "Sep 24",
    "commits": 62
  },
  {
    "name": "Sep 25",
    "commits": 2
  },
  {
    "name": "Sep 26",
    "commits": 0
  },
  {
    "name": "Sep 27",
    "commits": 1
  },
  {
    "name": "Sep 28",
    "commits": 5
  },
  {
    "name": "Sep 29",
    "commits": 34
  },
  {
    "name": "Sep 30",
    "commits": 46
  },
  {
    "name": "Oct 1",
    "commits": 6
  },
  {
    "name": "Oct 2",
    "commits": 15
  },
  {
    "name": "Oct 3",
    "commits": 15
  },
  {
    "name": "Oct 4",
    "commits": 17
  },
  {
    "name": "Oct 5",
    "commits": 11
  }
]
Counted with git log --no-merges, grouped by author date.

The milestones, in order

A timeline of ClarkCant milestones from git history, oldest first, in Asia/Saigon time. 16 September 2026 12:25: first commit. 28 September 22:30: product philosophy written into AGENTS.md (#202). 29 September 17:34: a labelled GitHub issue can be carried through to a draft pull request (#252). 29 September 23:00: Orb styles, six built-in plus Custom (#271). 30 September 00:29: the inbox reports uncertain outcomes, reminders and automations that come due (#268), with snooze and quieting at 01:25 (#272). 30 September 16:39: deleting conversations through a person-owned policy (#365). 30 September 21:45: Theme Lab and author CLI (#368). 2 October from 10:10: reference text editor, spreadsheet, AI image generator, media render tool and offline map (#383, #384, #392, #390, #398). 4 October 11:57: every turn records who started it, with an opt-in to be asked about machine-started turns (#446). 4 October 12:56: Clark can perform actions a widget offers, and by voice from 18:53 (#440, #457). 5 October 03:19: widgets pack as verified npm archives, the CLI and SDK built as npm packages, and three reference apps made npm-ready but not published (#465, #472, #473). 5 October 11:59: fallback model when the chosen one refuses a turn (#467). 5 October 12:47: a calmer interface pass (#474). 5 October 13:43: slash commands answered with command cards (#480).

Dates are the author dates of the commits named, in Asia/Saigon time.

One place for what is waiting on you

Clark runs work in the background, and background work has a nasty habit: it finishes, or gets stuck, while you're not looking. The inbox is the answer to two questions only. What is waiting for my decision? And how did the stuff I wasn't watching turn out?

The part I care most about is the uncertain case. When a background task runs a command against something outside your machine, a push, a message, a deletion, a payment, it is now written into a ledger before it starts. If the command is cut off or times out, we don't pretend it worked and we don't quietly run it again. It becomes one inbox notice that says what is uncertain, that nothing was re-run, and that you should check the other side first. Boring. Exactly what I'd want if it were my money.

You can snooze a notice, or quiet one narrow kind of notice, and undo that later. And the inbox is not a second home screen: every item points back to its own conversation, and deciding on the inbox or on the card in the chat is the same decision.

Clark stops failing in silence

Before, if the model you picked refused a turn, you got an error and that was that. Now Clark answers the same message on the next usable model and tells you, right under the reply, that a fallback model answered, which model you had chosen, and why it didn't. Your choice in Settings is not rewritten; the refusing model is skipped for a few minutes and then tried again. If every model refuses, the message names each one and its reason, and says your message is kept.

A smaller fix I'm weirdly proud of: after you approve a command, Clark continues with a short sentence written by the app. That sentence used to be stored as if you had typed it, so the transcript showed words in your bubble that you never wrote. It's now marked as host-written and drawn as a quiet line instead. Small thing. But a chat app that puts words in your mouth is not a chat app I'd trust.

TypeScript from packages/contracts/src/surfaces.ts starting at line 903: a versioned marker with kind host-continuation and version 1, and an isHostWrittenMessage function that returns true whenever a message carries a hostWritten field. The comment in that file says a client that meets an unknown kind or version still treats the message as host-written, so it never turns back into words put in the person's mouth.

Real code from #478.

Settings moved back into the conversation

The last commit as I write this adds slash commands that come back as command cards: /new starts a new conversation and keeps this one, /sessions lists background work and earlier conversations to reopen, /login and /logout sign in and out of AI providers inside the card, /thinking picks the thinking level, and /background runs a request beside the conversation. No settings page to hunt through. You type, or you ask, and the control appears where you already are.

The same day brought a big polish pass across 110 small commits squashed into one pull request. The ones you'll notice: a long run of working steps now folds into one line that says how many ran and how many failed, instead of twenty receipts stacked above the answer. You can choose the interface font and the code font. Markdown is marked while you type it. The desktop window reopens where you left it. And a lot of English labels in the Vietnamese interface finally speak Vietnamese.

Widgets that Clark, and your voice, can press

On 2 October a set of reference apps landed: a text editor, a spreadsheet, an AI image generator, a media render tool and a map that works over an offline basemap and only fetches tiles under a policy you set. Two days later, a widget became able to declare actions it offers, and Clark can perform one for you. The spreadsheet, for example, offers to format the selection; the editor offers replace. It goes through the same gate as everything else: your execution policy, the effect ledger, and an honest answer when the widget isn't open or doesn't reply in time. That evening the same path started working when you say it out loud.

For people who want to build their own widgets, the author CLI can now pack a widget into a verified npm archive and refuses one that carries credential-shaped files. The author CLI and SDK now build as npm packages, with a release workflow that smoke-tests the exact archives first. To be clear about the three pilot apps (Quick Notes, CSV Explorer, Media Converter): they are npm-ready, not on npm yet. The publish command prints what to run; it uploads nothing by itself.

Automation that finishes a job, and says who asked

A standing request you set up in conversation can now take a labelled GitHub issue all the way to a draft pull request: work in its own worktree, run the tests, commit, push with a token the node brokers, and tell the conversation the pull request's address. If GitHub can't reach your machine, the node polls the repository instead, at most every five minutes.

Once machines can start work, you need to know which turn came from you and which didn't. Every turn now records who started it: you, an MCP client, the relay, the CLI, an automation or a paired machine. Approval cards and the activity log say who asked. By default nothing changes in how decisions are made, but you can opt in to being asked before a risky effect that a machine-started turn causes.

What is not done, plainly

The README still says it on line one of the status section: this is a bootstrap, not a release. We keep a conformance ledger for the 18 scope items of the foundation beta. Ten are marked PASS. Eight are PARTIAL, and each one names what is missing.

The ones that matter most to a normal user: Google Calendar has never talked to Google, because there is no registered OAuth client and no Google account behind the tests; it runs end to end only against a stand-in API on the same machine. Live voice has never opened a real session, because there is no live provider account yet. Browser Use has only driven pages this repository serves, never a third-party site behind a login. Computer Use has no signed bundle and no container engine on the machine the tests ran on, so the native driver has never run. And installing a package through chat records an exact artifact but doesn't yet build its dependency tree.

I'd rather you read this here than discover it the hard way. None of these get marked done until a test proves them.

Table of the 18 scope items from docs/conformance-traceability.md. PASS (10): V01 Conversation client, V02 Portable runtime, V03 Persistent task/session runtime, V04 Trusted node linking, V05 Remote collaboration, V06 Workspace registry, V07 Capability platform, V11 Rich built-ins, V16 Onboarding/personalisation, V18 Operations/security. PARTIAL (8): V08 Conversational install (Dependency tree is not built yet), V09 Credential/auth setup (No registered OAuth client or live account), V10 Reference integration (Google Calendar) (Google itself has never been called), V12 Custom widgets (Voice and click parity needs a live voice session), V13 Pins (No live player vendor tested), V14 Browser Use (Never driven a third-party site behind a login), V15 Computer Use (No signed bundle, no container engine), V17 Live voice (No live provider account).

Underlying data
[
  {
    "id": "V01",
    "item": "Conversation client",
    "status": "PASS",
    "missing": ""
  },
  {
    "id": "V02",
    "item": "Portable runtime",
    "status": "PASS",
    "missing": ""
  },
  {
    "id": "V03",
    "item": "Persistent task/session runtime",
    "status": "PASS",
    "missing": ""
  },
  {
    "id": "V04",
    "item": "Trusted node linking",
    "status": "PASS",
    "missing": ""
  },
  {
    "id": "V05",
    "item": "Remote collaboration",
    "status": "PASS",
    "missing": ""
  },
  {
    "id": "V06",
    "item": "Workspace registry",
    "status": "PASS",
    "missing": ""
  },
  {
    "id": "V07",
    "item": "Capability platform",
    "status": "PASS",
    "missing": ""
  },
  {
    "id": "V08",
    "item": "Conversational install",
    "status": "PARTIAL",
    "missing": "Dependency tree is not built yet"
  },
  {
    "id": "V09",
    "item": "Credential/auth setup",
    "status": "PARTIAL",
    "missing": "No registered OAuth client or live account"
  },
  {
    "id": "V10",
    "item": "Reference integration (Google Calendar)",
    "status": "PARTIAL",
    "missing": "Google itself has never been called"
  },
  {
    "id": "V11",
    "item": "Rich built-ins",
    "status": "PASS",
    "missing": ""
  },
  {
    "id": "V12",
    "item": "Custom widgets",
    "status": "PARTIAL",
    "missing": "Voice and click parity needs a live voice session"
  },
  {
    "id": "V13",
    "item": "Pins",
    "status": "PARTIAL",
    "missing": "No live player vendor tested"
  },
  {
    "id": "V14",
    "item": "Browser Use",
    "status": "PARTIAL",
    "missing": "Never driven a third-party site behind a login"
  },
  {
    "id": "V15",
    "item": "Computer Use",
    "status": "PARTIAL",
    "missing": "No signed bundle, no container engine"
  },
  {
    "id": "V16",
    "item": "Onboarding/personalisation",
    "status": "PASS",
    "missing": ""
  },
  {
    "id": "V17",
    "item": "Live voice",
    "status": "PARTIAL",
    "missing": "No live provider account"
  },
  {
    "id": "V18",
    "item": "Operations/security",
    "status": "PASS",
    "missing": ""
  }
]
Sources: docs/conformance-traceability.md and packages/contracts/src/implementation-status.ts, as of 5 October 2026.

That's the two weeks. More fixes than I'd like to admit, a few things I'm genuinely happy with, and a clear list of what still needs the real world to prove it. If you want to push me on priorities, the survey below is the easiest way.

Which unproven piece should I prove against the real world first?