Skip to content

Commit 667392e

Browse files
os-zhuangclaude
andauthored
blog: the context-window argument, grounded in a real measurement (#3141)
The blog had two posts, both from January 2024, both written for the old positioning. This adds the post the site's current narrative actually needs, and fixes two rendering bugs the blog has carried the whole time. The post: "The Constraint Isn't Typing Speed. It's the Context Window." It deliberately does NOT lead with "~1% code surface" or "100× less code". Those numbers can't be honestly sourced — the traditional implementation they'd be measured against doesn't exist, so the ratio is a counterfactual, and the strongest in-repo data point (~300 → ~30 lines for one CRUD feature) is an order of magnitude off the claim anyway. What IS measurable is what shipped: examples/app-crm — six objects, views, a dashboard, a lead-conversion flow, permission sets, an action, translations — is 31 files / 1,792 lines / ~16k tokens. The whole business system, in 8% of a 200k window. The showcase app, which exercises every metadata type in the protocol, is ~101k and still leaves half a window free. Readers can re-run the count themselves; the post shows the command. That reframes the pitch from an efficiency claim (less code) to a capability claim (the agent can hold the entire dependency graph, so it can answer "what breaks if I change this?" instead of grepping and hoping) — and it closes on the catch, honestly: a small system is only useful if it's a correct one, which is what the validation gate is for. Also fixed, both found while checking the format: - Every post rendered its title twice — the detail page renders an <h1> from frontmatter, and both posts also opened with a duplicate `# H1`. - The index rendered posts in source order, so a new post could land anywhere. Now sorted newest-first, undated posts last. Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent a605872 commit 667392e

4 files changed

Lines changed: 158 additions & 3 deletions

File tree

apps/docs/app/[lang]/blog/[[...slug]]/page.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,13 @@ export default async function BlogPage({
2727

2828
// If no slug, show blog index
2929
if (!slug || slug.length === 0) {
30-
const posts = blog.getPages();
30+
// getPages() returns source order — newest first is the only order a blog
31+
// index should ever be in. Undated posts sort last rather than jumping.
32+
const posts = [...blog.getPages()].sort((a, b) => {
33+
const at = new Date((a.data as unknown as BlogPostData).date ?? 0).getTime();
34+
const bt = new Date((b.data as unknown as BlogPostData).date ?? 0).getTime();
35+
return bt - at;
36+
});
3137

3238
return (
3339
<HomeLayout {...baseOptions()}>
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
---
2+
title: "The Constraint Isn't Typing Speed. It's the Context Window."
3+
description: AI can write an enterprise app. Whether it can maintain one depends on whether the whole system fits in its head — which is an argument about the target format, not the model.
4+
author: ObjectStack Team
5+
date: 2026-07-17
6+
tags: [ai, architecture, metadata, positioning]
7+
---
8+
9+
Point a coding agent at an empty repository and ask for an expense-approval
10+
system. You'll get one. It'll have a schema, some endpoints, a couple of React
11+
screens, a permissions check or two. It'll take an afternoon instead of a
12+
quarter, and it'll mostly work.
13+
14+
Now come back in six weeks and ask for a change: expenses over $50k need a
15+
second approver from Finance.
16+
17+
This is where the afternoon's magic runs out. The agent has to find every place
18+
that assumed one approver — the schema, the approval logic, the UI that renders
19+
the button, the permission check, the notification text, the test fixtures.
20+
Twelve files, maybe thirty. It reads what it can, misses what it can't, and
21+
ships something that type-checks and quietly does the wrong thing on the 5% path
22+
nobody clicks until quarter-end.
23+
24+
The problem wasn't the model's intelligence. **The problem was that the system
25+
no longer fit in its head.**
26+
27+
## The number that actually matters
28+
29+
There's a temptation to sell AI-native development on volume: *N× less code, M×
30+
faster*. Those numbers are marketing until someone measures them, and the honest
31+
truth is that "how many lines would the traditional version have been?" is a
32+
counterfactual nobody can measure — because that version doesn't exist.
33+
34+
Here's what *can* be measured. This is a real, working CRM in this repository —
35+
[`examples/app-crm`](https://github.com/objectstack-ai/framework/tree/main/examples/app-crm):
36+
accounts, contacts, leads, opportunities with line items, activities. Views,
37+
a dashboard, a lead-conversion flow, permission sets, an action, translations.
38+
39+
| | |
40+
| :--- | :--- |
41+
| Files | 31 |
42+
| Lines | 1,792 |
43+
| Approximate tokens | ~16,000 |
44+
45+
That's the **entire business system**. Not a module of it — the data model, the
46+
UI, the automation, the access rules, all of it. It fits in about 8% of a
47+
200k-token context window.
48+
49+
The Todo example is ~14.5k tokens. The kitchen-sink showcase app — which
50+
deliberately exercises every metadata type in the protocol, 83 files of it — is
51+
~101k. Even that one, the maximalist case, leaves half a modern context window
52+
free for the actual work.
53+
54+
Measure your own:
55+
56+
```bash
57+
find src -name '*.ts' -not -name '*.test.ts' | xargs cat | wc -l
58+
```
59+
60+
## Why "fits in the window" is a different claim
61+
62+
"Less code" is an efficiency argument. **"Fits in the window" is a capability
63+
argument** — it changes what the agent is able to do at all, not how fast it
64+
does it.
65+
66+
An agent that can hold the whole system at once can answer questions that an
67+
agent working through a 40k-file repository fundamentally cannot:
68+
69+
- *Which things break if I add a second approver?* — It can see every consumer
70+
of the approval, because every consumer is in the same few thousand lines.
71+
- *Is this change safe?* — It can check the permission set against the view
72+
against the flow, in one pass, without hoping its grep found everything.
73+
- *What did I miss?* — There's no "somewhere else in the codebase" for a
74+
dependency to hide in.
75+
76+
This is the line between an agent that autocompletes and an agent that
77+
maintains. Retrieval helps a model *find* things; it doesn't give it the whole
78+
dependency graph at once. And for the change above, the whole graph is exactly
79+
what you need.
80+
81+
## How the system gets small
82+
83+
It isn't compression, and it isn't a clever DSL. It's that most of an enterprise
84+
app was never business-specific to begin with.
85+
86+
Pagination. Sort order. Optimistic concurrency. Foreign-key resolution. Form
87+
validation mirrored on the client and the server. Audit rows. Permission checks
88+
on every endpoint. The list view that needs a filter bar. **None of that is your
89+
business** — it's the same in every CRM ever written, and traditionally you (or
90+
your agent) rewrite it per app, per screen, because there's nowhere else to put
91+
it.
92+
93+
Put it in the runtime instead, and what's left in the source is the part that's
94+
actually yours:
95+
96+
```ts
97+
export const Opportunity = ObjectSchema.create({
98+
name: 'crm_opportunity',
99+
label: 'Opportunity',
100+
sharingModel: 'private',
101+
fields: {
102+
name: Field.text({ label: 'Opportunity Name', required: true }),
103+
account: Field.lookup('crm_account', { label: 'Account', required: true }),
104+
amount: Field.currency({ label: 'Amount', min: 0 }),
105+
probability: Field.percent({ label: 'Probability', defaultValue: 0.5 }),
106+
expected_revenue: Field.formula({
107+
label: 'Expected Revenue',
108+
expression: cel`amount * probability`,
109+
}),
110+
},
111+
});
112+
```
113+
114+
From that, the runtime derives the table, the REST endpoints, the list and form
115+
UI, and the MCP tools an agent can call. There is no generated code sitting in
116+
your repo that has to be regenerated, reviewed, and kept in sync — the surface
117+
*is* the definition, and the definition is what you read.
118+
119+
This is what ObjectStack is for. Not "a framework that writes less code" —
120+
**a target format small enough that the thing writing it can also understand
121+
it.**
122+
123+
## The catch, stated plainly
124+
125+
A small system is only useful if it's a *correct* small system, and compactness
126+
cuts both ways: a one-line mistake in a few hundred lines of metadata is
127+
proportionally a much bigger mistake.
128+
129+
Worse, the errors that matter here mostly don't crash. A predicate that
130+
references a field the wrong way doesn't throw — it evaluates to nothing, the
131+
button silently never renders, and you find out when a user asks why they can't
132+
resolve a ticket. TypeScript won't catch it: the predicate is a string, and the
133+
string is a perfectly valid string.
134+
135+
That's why the gate exists. `os validate` runs the checks a type system
136+
structurally cannot: CEL predicates actually parse and reference fields that
137+
exist, widget bindings point at datasets that exist, every custom object
138+
declares its access baseline. It rejects at authoring time, with a located
139+
error the agent can read and fix in the same breath — which is the other half of
140+
why the host language is TypeScript. Not because it's fashionable, but because
141+
an agent's mistakes come back as *text it can act on*, seconds after it made
142+
them, instead of as a silent runtime failure six weeks later.
143+
144+
Small enough to fit. Strict enough to be worth fitting. That's the whole bet.
145+
146+
---
147+
148+
**Try the measurement yourself:** `npm create objectstack@latest my-app`, build
149+
something with your agent, then count the lines. If the whole app doesn't fit in
150+
your agent's context window, we'd like to hear about it — that's a bug in the
151+
target format, and the format is [open](https://github.com/objectstack-ai/framework).

content/blog/metadata-driven-architecture.mdx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ date: 2024-01-20
66
tags: [architecture, metadata, enterprise, analysis]
77
---
88

9-
# The Architecture of Metadata-Driven Systems: From Salesforce to ObjectStack
109

1110
## Introduction: The Metadata Revolution
1211

content/blog/protocol-first-development.mdx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ date: 2024-01-22
66
tags: [protocol, architecture, open-source, philosophy, technical]
77
---
88

9-
# Protocol-First Development: Why ObjectStack Chose Open Standards Over Proprietary Platforms
109

1110
## Introduction: The Platform Trap
1211

0 commit comments

Comments
 (0)