ralphify 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ralphify-0.1.0/.gitignore +5 -0
- ralphify-0.1.0/PKG-INFO +7 -0
- ralphify-0.1.0/context/blog_posts/harness_engineering_openai.md +235 -0
- ralphify-0.1.0/context/blog_posts/ralph_wiggum_as_a_software_engineer.md +400 -0
- ralphify-0.1.0/pyproject.toml +16 -0
- ralphify-0.1.0/src/ralphify/__init__.py +7 -0
- ralphify-0.1.0/src/ralphify/cli.py +106 -0
- ralphify-0.1.0/src/ralphify/detector.py +15 -0
- ralphify-0.1.0/uv.lock +115 -0
ralphify-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
URL: https://openai.com/index/harness-engineering/
|
|
2
|
+
|
|
3
|
+
February 11, 2026
|
|
4
|
+
|
|
5
|
+
Engineering
|
|
6
|
+
Harness engineering: leveraging Codex in an agent-first world
|
|
7
|
+
By Ryan Lopopolo, Member of the Technical Staff
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
Listen to article
|
|
11
|
+
18:04
|
|
12
|
+
Share
|
|
13
|
+
Over the past five months, our team has been running an experiment: building and shipping an internal beta of a software product with 0 lines of manually-written code.
|
|
14
|
+
|
|
15
|
+
The product has internal daily users and external alpha testers. It ships, deploys, breaks, and gets fixed. What’s different is that every line of code—application logic, tests, CI configuration, documentation, observability, and internal tooling—has been written by Codex. We estimate that we built this in about 1/10th the time it would have taken to write the code by hand.
|
|
16
|
+
|
|
17
|
+
Humans steer. Agents execute.
|
|
18
|
+
|
|
19
|
+
We intentionally chose this constraint so we would build what was necessary to increase engineering velocity by orders of magnitude. We had weeks to ship what ended up being a million lines of code. To do that, we needed to understand what changes when a software engineering team’s primary job is no longer to write code, but to design environments, specify intent, and build feedback loops that allow Codex agents to do reliable work.
|
|
20
|
+
|
|
21
|
+
This post is about what we learned by building a brand new product with a team of agents—what broke, what compounded, and how to maximize our one truly scarce resource: human time and attention.
|
|
22
|
+
|
|
23
|
+
We started with an empty git repository
|
|
24
|
+
The first commit to an empty repository landed in late August 2025.
|
|
25
|
+
|
|
26
|
+
The initial scaffold—repository structure, CI configuration, formatting rules, package manager setup, and application framework—was generated by Codex CLI using GPT‑5, guided by a small set of existing templates. Even the initial AGENTS.md file that directs agents how to work in the repository was itself written by Codex.
|
|
27
|
+
|
|
28
|
+
There was no pre-existing human-written code to anchor the system. From the beginning, the repository was shaped by the agent.
|
|
29
|
+
|
|
30
|
+
Five months later, the repository contains on the order of a million lines of code across application logic, infrastructure, tooling, documentation, and internal developer utilities. Over that period, roughly 1,500 pull requests have been opened and merged with a small team of just three engineers driving Codex. This translates to an average throughput of 3.5 PRs per engineer per day, and surprisingly the throughput has increased as the team has grown to now seven engineers. Importantly, this wasn’t output for output’s sake: the product has been used by hundreds of users internally, including daily internal power users.
|
|
31
|
+
|
|
32
|
+
Throughout the development process, humans never directly contributed any code. This became a core philosophy for the team: no manually-written code.
|
|
33
|
+
|
|
34
|
+
Redefining the role of the engineer
|
|
35
|
+
The lack of hands-on human coding introduced a different kind of engineering work, focused on systems, scaffolding, and leverage.
|
|
36
|
+
|
|
37
|
+
Early progress was slower than we expected, not because Codex was incapable, but because the environment was underspecified. The agent lacked the tools, abstractions, and internal structure required to make progress toward high-level goals. The primary job of our engineering team became enabling the agents to do useful work.
|
|
38
|
+
|
|
39
|
+
In practice, this meant working depth-first: breaking down larger goals into smaller building blocks (design, code, review, test, etc), prompting the agent to construct those blocks, and using them to unlock more complex tasks. When something failed, the fix was almost never “try harder.” Because the only way to make progress was to get Codex to do the work, human engineers always stepped into the task and asked: “what capability is missing, and how do we make it both legible and enforceable for the agent?”
|
|
40
|
+
|
|
41
|
+
Humans interact with the system almost entirely through prompts: an engineer describes a task, runs the agent, and allows it to open a pull request. To drive a PR to completion, we instruct Codex to review its own changes locally, request additional specific agent reviews both locally and in the cloud, respond to any human or agent given feedback, and iterate in a loop until all agent reviewers are satisfied (effectively this is a Ralph Wiggum Loop(opens in a new window)). Codex uses our standard development tools directly (gh, local scripts, and repository-embedded skills) to gather context without humans copying and pasting into the CLI.
|
|
42
|
+
|
|
43
|
+
Humans may review pull requests, but aren’t required to. Over time, we’ve pushed almost all review effort towards being handled agent-to-agent.
|
|
44
|
+
|
|
45
|
+
Increasing application legibility
|
|
46
|
+
As code throughput increased, our bottleneck became human QA capacity. Because the fixed constraint has been human time and attention, we’ve worked to add more capabilities to the agent by making things like the application UI, logs, and app metrics themselves directly legible to Codex.
|
|
47
|
+
|
|
48
|
+
For example, we made the app bootable per git worktree, so Codex could launch and drive one instance per change. We also wired the Chrome DevTools Protocol into the agent runtime and created skills for working with DOM snapshots, screenshots, and navigation. This enabled Codex to reproduce bugs, validate fixes, and reason about UI behavior directly.
|
|
49
|
+
|
|
50
|
+
Diagram titled “Codex drives the app with Chrome DevTools MCP to validate its work.” Codex selects a target, snapshots the state before and after triggering a UI path, observes runtime events via Chrome DevTools, applies fixes, restarts, and loops re-running validation until the app is clean.
|
|
51
|
+
We did the same for observability tooling. Logs, metrics, and traces are exposed to Codex via a local observability stack that’s ephemeral for any given worktree. Codex works on a fully isolated version of that app—including its logs and metrics, which get torn down once that task is complete. Agents can query logs with LogQL and metrics with PromQL. With this context available, prompts like “ensure service startup completes in under 800ms” or “no span in these four critical user journeys exceeds two seconds” become tractable.
|
|
52
|
+
|
|
53
|
+
Diagram titled “Giving Codex a full observability stack in local dev.” An app sends logs, metrics, and traces to Vector, which fans out data to an observability stack containing Victoria Logs, Metrics, and Traces, each queried via LogQL, PromQL, or TraceQL APIs. Codex uses these signals to query, correlate, and reason, then implements fixes in the codebase, restarts the app, re-runs workloads, tests UI journeys, and repeats in a feedback loop.
|
|
54
|
+
We regularly see single Codex runs work on a single task for upwards of six hours (often while the humans are sleeping).
|
|
55
|
+
|
|
56
|
+
We made repository knowledge the system of record
|
|
57
|
+
Context management is one of the biggest challenges in making agents effective at large and complex tasks. One of the earliest lessons we learned was simple: give Codex a map, not a 1,000-page instruction manual.
|
|
58
|
+
|
|
59
|
+
We tried the “one big AGENTS.md(opens in a new window)” approach. It failed in predictable ways:
|
|
60
|
+
|
|
61
|
+
Context is a scarce resource. A giant instruction file crowds out the task, the code, and the relevant docs—so the agent either misses key constraints or starts optimizing for the wrong ones.
|
|
62
|
+
Too much guidance becomes non-guidance. When everything is “important,” nothing is. Agents end up pattern-matching locally instead of navigating intentionally.
|
|
63
|
+
It rots instantly. A monolithic manual turns into a graveyard of stale rules. Agents can’t tell what’s still true, humans stop maintaining it, and the file quietly becomes an attractive nuisance.
|
|
64
|
+
It’s hard to verify. A single blob doesn’t lend itself to mechanical checks (coverage, freshness, ownership, cross-links), so drift is inevitable.
|
|
65
|
+
So instead of treating AGENTS.md as the encyclopedia, we treat it as the table of contents.
|
|
66
|
+
|
|
67
|
+
The repository’s knowledge base lives in a structured docs/ directory treated as the system of record. A short AGENTS.md (roughly 100 lines) is injected into context and serves primarily as a map, with pointers to deeper sources of truth elsewhere.
|
|
68
|
+
|
|
69
|
+
Plain Text
|
|
70
|
+
|
|
71
|
+
1
|
|
72
|
+
AGENTS.md
|
|
73
|
+
2
|
|
74
|
+
ARCHITECTURE.md
|
|
75
|
+
3
|
|
76
|
+
docs/
|
|
77
|
+
4
|
|
78
|
+
├── design-docs/
|
|
79
|
+
5
|
|
80
|
+
│ ├── index.md
|
|
81
|
+
6
|
|
82
|
+
│ ├── core-beliefs.md
|
|
83
|
+
7
|
|
84
|
+
│ └── ...
|
|
85
|
+
8
|
|
86
|
+
├── exec-plans/
|
|
87
|
+
9
|
|
88
|
+
│ ├── active/
|
|
89
|
+
10
|
|
90
|
+
│ ├── completed/
|
|
91
|
+
11
|
|
92
|
+
│ └── tech-debt-tracker.md
|
|
93
|
+
12
|
|
94
|
+
├── generated/
|
|
95
|
+
13
|
|
96
|
+
│ └── db-schema.md
|
|
97
|
+
14
|
|
98
|
+
├── product-specs/
|
|
99
|
+
15
|
|
100
|
+
│ ├── index.md
|
|
101
|
+
16
|
|
102
|
+
│ ├── new-user-onboarding.md
|
|
103
|
+
17
|
|
104
|
+
│ └── ...
|
|
105
|
+
18
|
|
106
|
+
├── references/
|
|
107
|
+
19
|
|
108
|
+
│ ├── design-system-reference-llms.txt
|
|
109
|
+
20
|
|
110
|
+
│ ├── nixpacks-llms.txt
|
|
111
|
+
21
|
|
112
|
+
│ ├── uv-llms.txt
|
|
113
|
+
22
|
|
114
|
+
│ └── ...
|
|
115
|
+
23
|
|
116
|
+
├── DESIGN.md
|
|
117
|
+
24
|
|
118
|
+
├── FRONTEND.md
|
|
119
|
+
25
|
|
120
|
+
├── PLANS.md
|
|
121
|
+
26
|
|
122
|
+
├── PRODUCT_SENSE.md
|
|
123
|
+
27
|
|
124
|
+
├── QUALITY_SCORE.md
|
|
125
|
+
28
|
|
126
|
+
├── RELIABILITY.md
|
|
127
|
+
29
|
|
128
|
+
└── SECURITY.md
|
|
129
|
+
In-repository knowledge store layout.
|
|
130
|
+
|
|
131
|
+
Design documentation is catalogued and indexed, including verification status and a set of core beliefs that define agent-first operating principles. Architecture documentation(opens in a new window) provides a top-level map of domains and package layering. A quality document grades each product domain and architectural layer, tracking gaps over time.
|
|
132
|
+
|
|
133
|
+
Plans are treated as first-class artifacts. Ephemeral lightweight plans are used for small changes, while complex work is captured in execution plans(opens in a new window) with progress and decision logs that are checked into the repository. Active plans, completed plans, and known technical debt are all versioned and co-located, allowing agents to operate without relying on external context.
|
|
134
|
+
|
|
135
|
+
This enables progressive disclosure: agents start with a small, stable entry point and are taught where to look next, rather than being overwhelmed up front.
|
|
136
|
+
|
|
137
|
+
We enforce this mechanically. Dedicated linters and CI jobs validate that the knowledge base is up to date, cross-linked, and structured correctly. A recurring “doc-gardening” agent scans for stale or obsolete documentation that does not reflect the real code behavior and opens fix-up pull requests.
|
|
138
|
+
|
|
139
|
+
Agent legibility is the goal
|
|
140
|
+
As the codebase evolved, Codex’s framework for design decisions needed to evolve, too.
|
|
141
|
+
|
|
142
|
+
Because the repository is entirely agent-generated, it’s optimized first for Codex’s legibility. In the same way teams aim to improve navigability of their code for new engineering hires, our human engineers’ goal was making it possible for an agent to reason about the full business domain directly from the repository itself.
|
|
143
|
+
|
|
144
|
+
From the agent’s point of view, anything it can’t access in-context while running effectively doesn’t exist. Knowledge that lives in Google Docs, chat threads, or people’s heads are not accessible to the system. Repository-local, versioned artifacts (e.g., code, markdown, schemas, executable plans) are all it can see.
|
|
145
|
+
|
|
146
|
+
Diagram titled “The limits of agent knowledge: What Codex can’t see doesn’t exist.” Codex’s knowledge is shown as a bounded bubble. Below it are examples of unseen knowledge—Google Docs, Slack messages, and tacit human knowledge. Arrows indicate that to make this information visible to Codex, it must be encoded into the codebase as markdown.
|
|
147
|
+
We learned that we needed to push more and more context into the repo over time. That Slack discussion that aligned the team on an architectural pattern? If it isn’t discoverable to the agent, it’s illegible in the same way it would be unknown to a new hire joining three months later.
|
|
148
|
+
|
|
149
|
+
Giving Codex more context means organizing and exposing the right information so the agent can reason over it, rather than overwhelming it with ad-hoc instructions. In the same way you would onboard a new teammate on product principles, engineering norms, and team culture (emoji preferences included), giving the agent this information leads to better-aligned output.
|
|
150
|
+
|
|
151
|
+
This framing clarified many tradeoffs. We favored dependencies and abstractions that could be fully internalized and reasoned about in-repo. Technologies often described as “boring” tend to be easier for agents to model due to composability, api stability, and representation in the training set. In some cases, it was cheaper to have the agent reimplement subsets of functionality than to work around opaque upstream behavior from public libraries. For example, rather than pulling in a generic p-limit-style package, we implemented our own map-with-concurrency helper: it’s tightly integrated with our OpenTelemetry instrumentation, has 100% test coverage, and behaves exactly the way our runtime expects.
|
|
152
|
+
|
|
153
|
+
Pulling more of the system into a form the agent can inspect, validate, and modify directly increases leverage—not just for Codex, but for other agents (e.g. Aardvark) that are working on the codebase as well.
|
|
154
|
+
|
|
155
|
+
Enforcing architecture and taste
|
|
156
|
+
Documentation alone doesn’t keep a fully agent-generated codebase coherent. By enforcing invariants, not micromanaging implementations, we let agents ship fast without undermining the foundation. For example, we require Codex to parse data shapes at the boundary(opens in a new window), but are not prescriptive on how that happens (the model seems to like Zod, but we didn’t specify that specific library).
|
|
157
|
+
|
|
158
|
+
Agents are most effective in environments with strict boundaries and predictable structure(opens in a new window), so we built the application around a rigid architectural model. Each business domain is divided into a fixed set of layers, with strictly validated dependency directions and a limited set of permissible edges. These constraints are enforced mechanically via custom linters (Codex-generated, of course!) and structural tests.
|
|
159
|
+
|
|
160
|
+
The diagram below shows the rule: within each business domain (e.g. App Settings), code can only depend “forward” through a fixed set of layers (Types → Config → Repo → Service → Runtime → UI). Cross-cutting concerns (auth, connectors, telemetry, feature flags) enter through a single explicit interface: Providers. Anything else is disallowed and enforced mechanically.
|
|
161
|
+
|
|
162
|
+
Diagram titled “Layered domain architecture with explicit cross-cutting boundaries.” Inside the business logic domain are modules: Types → Config → Repo, and Providers → Service → Runtime → UI, with App Wiring + UI at the bottom. A Utils module sits outside the boundary and feeds into Providers.
|
|
163
|
+
This is the kind of architecture you usually postpone until you have hundreds of engineers. With coding agents, it’s an early prerequisite: the constraints are what allows speed without decay or architectural drift.
|
|
164
|
+
|
|
165
|
+
In practice, we enforce these rules with custom linters and structural tests, plus a small set of “taste invariants.” For example, we statically enforce structured logging, naming conventions for schemas and types, file size limits, and platform-specific reliability requirements with custom lints. Because the lints are custom, we write the error messages to inject remediation instructions into agent context.
|
|
166
|
+
|
|
167
|
+
In a human-first workflow, these rules might feel pedantic or constraining. With agents, they become multipliers: once encoded, they apply everywhere at once.
|
|
168
|
+
|
|
169
|
+
At the same time, we’re explicit about where constraints matter and where they do not. This resembles leading a large engineering platform organization: enforce boundaries centrally, allow autonomy locally. You care deeply about boundaries, correctness, and reproducibility. Within those boundaries, you allow teams—or agents—significant freedom in how solutions are expressed.
|
|
170
|
+
|
|
171
|
+
The resulting code does not always match human stylistic preferences, and that’s okay. As long as the output is correct, maintainable, and legible to future agent runs, it meets the bar.
|
|
172
|
+
|
|
173
|
+
Human taste is fed back into the system continuously. Review comments, refactoring pull requests, and user-facing bugs are captured as documentation updates or encoded directly into tooling. When documentation falls short, we promote the rule into code
|
|
174
|
+
|
|
175
|
+
Throughput changes the merge philosophy
|
|
176
|
+
As Codex’s throughput increased, many conventional engineering norms became counterproductive.
|
|
177
|
+
|
|
178
|
+
The repository operates with minimal blocking merge gates. Pull requests are short-lived. Test flakes are often addressed with follow-up runs rather than blocking progress indefinitely. In a system where agent throughput far exceeds human attention, corrections are cheap, and waiting is expensive.
|
|
179
|
+
|
|
180
|
+
This would be irresponsible in a low-throughput environment. Here, it’s often the right tradeoff.
|
|
181
|
+
|
|
182
|
+
What “agent-generated” actually means
|
|
183
|
+
When we say the codebase is generated by Codex agents, we mean everything in the codebase.
|
|
184
|
+
|
|
185
|
+
Agents produce:
|
|
186
|
+
|
|
187
|
+
Product code and tests
|
|
188
|
+
CI configuration and release tooling
|
|
189
|
+
Internal developer tools
|
|
190
|
+
Documentation and design history
|
|
191
|
+
Evaluation harnesses
|
|
192
|
+
Review comments and responses
|
|
193
|
+
Scripts that manage the repository itself
|
|
194
|
+
Production dashboard definition files
|
|
195
|
+
Humans always remain in the loop, but work at a different layer of abstraction than we used to. We prioritize work, translate user feedback into acceptance criteria, and validate outcomes. When the agent struggles, we treat it as a signal: identify what is missing—tools, guardrails, documentation—and feed it back into the repository, always by having Codex itself write the fix.
|
|
196
|
+
|
|
197
|
+
Agents use our standard development tools directly. They pull review feedback, respond inline, push updates, and often squash and merge their own pull requests.
|
|
198
|
+
|
|
199
|
+
Increasing levels of autonomy
|
|
200
|
+
As more of the development loop was encoded directly into the system—testing, validation, review, feedback handling, and recovery—the repository recently crossed a meaningful threshold where Codex can end-to-end drive a new feature.
|
|
201
|
+
|
|
202
|
+
Given a single prompt, the agent can now:
|
|
203
|
+
|
|
204
|
+
Validate the current state of the codebase
|
|
205
|
+
Reproduce a reported bug
|
|
206
|
+
Record a video demonstrating the failure
|
|
207
|
+
Implement a fix
|
|
208
|
+
Validate the fix by driving the application
|
|
209
|
+
Record a second video demonstrating the resolution
|
|
210
|
+
Open a pull request
|
|
211
|
+
Respond to agent and human feedback
|
|
212
|
+
Detect and remediate build failures
|
|
213
|
+
Escalate to a human only when judgment is required
|
|
214
|
+
Merge the change
|
|
215
|
+
This behavior depends heavily on the specific structure and tooling of this repository and should not be assumed to generalize without similar investment—at least, not yet.
|
|
216
|
+
|
|
217
|
+
Entropy and garbage collection
|
|
218
|
+
Full agent autonomy also introduces novel problems. Codex replicates patterns that already exist in the repository—even uneven or suboptimal ones. Over time, this inevitably leads to drift.
|
|
219
|
+
|
|
220
|
+
Initially, humans addressed this manually. Our team used to spend every Friday (20% of the week) cleaning up “AI slop.” Unsurprisingly, that didn’t scale.
|
|
221
|
+
|
|
222
|
+
Instead, we started encoding what we call “golden principles” directly into the repository and built a recurring cleanup process. These principles are opinionated, mechanical rules that keep the codebase legible and consistent for future agent runs. For example: (1) we prefer shared utility packages over hand-rolled helpers to keep invariants centralized, and (2) we don’t probe data “YOLO-style”—we validate boundaries or rely on typed SDKs so the agent can’t accidentally build on guessed shapes. On a regular cadence, we have a set of background Codex tasks that scan for deviations, update quality grades, and open targeted refactoring pull requests. Most of these can be reviewed in under a minute and automerged.
|
|
223
|
+
|
|
224
|
+
This functions like garbage collection. Technical debt is like a high-interest loan: it’s almost always better to pay it down continuously in small increments than to let it compound and tackle it in painful bursts. Human taste is captured once, then enforced continuously on every line of code. This also lets us catch and resolve bad patterns on a daily basis, rather than letting them spread in the code base for days or weeks.
|
|
225
|
+
|
|
226
|
+
What we’re still learning
|
|
227
|
+
This strategy has so far worked well up through internal launch and adoption at OpenAI. Building a real product for real users helped anchor our investments in reality and guide us towards long-term maintainability.
|
|
228
|
+
|
|
229
|
+
What we don’t yet know is how architectural coherence evolves over years in a fully agent-generated system. We’re still learning where human judgment adds the most leverage and how to encode that judgment so it compounds. We also don’t know how this system will evolve as models continue to become more capable over time.
|
|
230
|
+
|
|
231
|
+
What’s become clear: building software still demands discipline, but the discipline shows up more in the scaffolding rather than the code. The tooling, abstractions, and feedback loops that keep the codebase coherent are increasingly important.
|
|
232
|
+
|
|
233
|
+
Our most difficult challenges now center on designing environments, feedback loops, and control systems that help agents accomplish our goal: build and maintain complex, reliable software at scale.
|
|
234
|
+
|
|
235
|
+
As agents like Codex take on larger portions of the software lifecycle, these questions will matter even more. We hope that sharing some early lessons helps you reason about where to invest your effort so you can just build things.
|
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
https://ghuntley.com/ralph/
|
|
2
|
+
|
|
3
|
+
By Geoffrey Huntley in AI — 14 Jul 2025
|
|
4
|
+
Ralph Wiggum as a "software engineer"
|
|
5
|
+
Ralph Wiggum as a "software engineer"
|
|
6
|
+
How Ralph Wiggum went from 'The Simpsons' to the biggest name in AI right now - Venture Beat
|
|
7
|
+
|
|
8
|
+
watch this to see it in practice and learn the theory; read below to go deeper
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
watch this to learn why the claude code plugin isn’t it 🤝
|
|
12
|
+
|
|
13
|
+
😎
|
|
14
|
+
Here's a cool little field report from a Y Combinator hackathon event where they put Ralph Wiggum to the test.
|
|
15
|
+
|
|
16
|
+
"We Put a Coding Agent in a While Loop and It Shipped 6 Repos Overnight"
|
|
17
|
+
|
|
18
|
+
https://github.com/repomirrorhq/repomirror/blob/main/repomirror.md
|
|
19
|
+
If you've seen my socials lately, you might have seen me talking about Ralph and wondering what Ralph is. Ralph is a technique. In its purest form, Ralph is a Bash loop.
|
|
20
|
+
|
|
21
|
+
while :; do cat PROMPT.md | claude-code ; done
|
|
22
|
+
Ralph can replace the majority of outsourcing at most companies for greenfield projects. It has defects, but these are identifiable and resolvable through various styles of prompts.
|
|
23
|
+
|
|
24
|
+
That's the beauty of Ralph - the technique is deterministically bad in an undeterministic world.
|
|
25
|
+
Ralph can be done with any tool that does not cap tool calls and usage.
|
|
26
|
+
|
|
27
|
+
Ralph is currently building a brand new programming language. We are on the final leg before a brand new production-grade esoteric programming language is released. What's kind of wild to me is that Ralph has been able to build this language and is also able to program in this language without that language being in the LLM's training data set.
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
Building software with Ralph requires a great deal of faith and a belief in eventual consistency. Ralph will test you. Every time Ralph has taken a wrong direction in making CURSED, I haven't blamed the tools; instead, I've looked inside. Each time Ralph does something bad, Ralph gets tuned - like a guitar.
|
|
31
|
+
|
|
32
|
+
deliberate intentional practice
|
|
33
|
+
Something I’ve been wondering about for a really long time is, essentially, why do people say AI doesn’t work for them? What do they mean when they say that? From which identity are they coming from? Are they coming from the perspective of an engineer with a job title and
|
|
34
|
+
|
|
35
|
+
Geoffrey Huntley
|
|
36
|
+
Geoffrey Huntley
|
|
37
|
+
|
|
38
|
+
LLMs are mirrors of operator skill
|
|
39
|
+
This is a follow-up from my previous blog post: “deliberate intentional practice”. I didn’t want to get into the distinction between skilled and unskilled because people take offence to it, but AI is a matter of skill. Someone can be highly experienced as a software engineer in 2024, but that
|
|
40
|
+
|
|
41
|
+
Geoffrey Huntley
|
|
42
|
+
Geoffrey Huntley
|
|
43
|
+
|
|
44
|
+
It begins with no playground, and Ralph is given instructions to construct one.
|
|
45
|
+
|
|
46
|
+
Ralph is very good at making playgrounds, but he comes home bruised because he fell off the slide, so one then tunes Ralph by adding a sign next to the slide saying “SLIDE DOWN, DON’T JUMP, LOOK AROUND,” and Ralph is more likely to look and see the sign.
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
Eventually all Ralph thinks about is the signs so that’s when you get a new Ralph that doesn't feel defective like Ralph, at all.
|
|
50
|
+
|
|
51
|
+
When I was in SFO, I taught a few smart people about Ralph. One incredibly talented engineer listened and used Ralph on their next contract, walking away with the wildest ROI. These days, all they think about is Ralph.
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
what's in the prompt.md? can I have it?
|
|
55
|
+
There seems to be an obsession in the programming community with the perfect prompt. There is no such thing as a perfect prompt.
|
|
56
|
+
|
|
57
|
+
Whilst it might be tempting to take the prompt from CURSED, it won't make sense unless you know how to wield it. You probably won't get the same outcomes by taking the prompt verbatim, because it has evolved through continual tuning based on observation of LLM behaviour. When CURSED is being built, I'm sitting there watching the stream, looking for patterns of bad behaviour—opportunities to tune Ralph.
|
|
58
|
+
|
|
59
|
+
first some fundamentals
|
|
60
|
+
While I was in SFO, everyone seemed to be trying to crack on multi-agent, agent-to-agent communication and multiplexing. At this stage, it's not needed. Consider microservices and all the complexities that come with them. Now, consider what microservices would look like if the microservices (agents) themselves are non-deterministic—a red hot mess.
|
|
61
|
+
|
|
62
|
+
What's the opposite of microservices? A monolithic application. A single operating system process that scales vertically. Ralph is monolithic. Ralph works autonomously in a single repository as a single process that performs one task per loop.
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
the ralph wiggum technique as a diagram
|
|
66
|
+
To get good outcomes with Ralph, you need to ask Ralph to do one thing per loop. Only one thing. Now, this might seem wild, but you also need to trust Ralph to decide what's the most important thing to implement. This is full hands-off vibe coding that will test the bounds of what you consider "responsible engineering".
|
|
67
|
+
|
|
68
|
+
LLMs are surprisingly good at reasoning about what is important to implement and what the next steps are.
|
|
69
|
+
|
|
70
|
+
Your task is to implement missing stdlib (see @specs/stdlib/*) and compiler functionality and produce an compiled application in the cursed language via LLVM for that functionality using parrallel subagents. Follow the @fix_plan.md and choose the most important thing.
|
|
71
|
+
There's a few things in the above prompt which I'll expand upon shortly but the other key thing is deterministically allocate the stack the same way every loop.
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
The items that you want to allocate to the stack every loop are your plan ("@fix_plan.md") and your specifications. See below if specs are a new concept to you.
|
|
75
|
+
|
|
76
|
+
From Design doc to code: the Groundhog AI coding assistant (and new Cursor vibecoding meta)
|
|
77
|
+
Ello everyone, in the “Yes, Claude Code can decompile itself. Here’s the source code” blog post, I teased about a new meta when using Cursor. This post is a follow-up to the post below. You are using Cursor AI incorrectly...I’m hesitant to give this advice away for free,
|
|
78
|
+
|
|
79
|
+
Geoffrey Huntley
|
|
80
|
+
Geoffrey Huntley
|
|
81
|
+
|
|
82
|
+
Specs are formed through a conversation with the agent at the beginning phase of a project. Instead of asking the agent to implement the project, what you want to do is have a long conversation with the LLM about your requirements for what you're about to implement. Once your agent has a decent understanding of the task to be done, it's at that point that you issue a prompt to write the specifications out, one per file, in the specifications folder.
|
|
83
|
+
|
|
84
|
+
one item per loop
|
|
85
|
+
One item per loop. I need to repeat myself here—one item per loop. You may relax this restriction as the project progresses, but if it starts going off the rails, then you need to narrow it down to just one item.
|
|
86
|
+
|
|
87
|
+
The name of the game is that you only have approximately 170k of context window to work with. So it's essential to use as little of it as possible. The more you use the context window, the worse the outcomes you'll get. Yes, this is wasteful because you're effectively burning the allocation of the specifications every loop and not reusing the allocation.
|
|
88
|
+
|
|
89
|
+
extend the context window
|
|
90
|
+
The way that agentic loops work is by executing a tool and then evaluating the result of that tool. The evaluation results in an allocation being added to your context window. See below.
|
|
91
|
+
|
|
92
|
+
autoregressive queens of failure
|
|
93
|
+
Have you ever had your AI coding assistant suggest something so off-base that you wonder if it’s trolling you? Welcome to the world of autoregressive failure. LLMs, the brains behind these assistants, are great at predicting the next word—or line of code—based on what’s been fed into
|
|
94
|
+
|
|
95
|
+
Geoffrey Huntley
|
|
96
|
+
Geoffrey Huntley
|
|
97
|
+
|
|
98
|
+
Ralph requires a mindset of not allocating to the primary context window. Instead, what you should do is spawn subagents. Your primary context window should operate as a scheduler, scheduling other subagents to perform expensive allocation-type work, such as summarising whether your test suite worked.
|
|
99
|
+
|
|
100
|
+
I dream about AI subagents; they whisper to me while I’m asleep
|
|
101
|
+
In a previous post, I shared about “real context window” sizes and “advertised context window sizes” Claude 3.7’s advertised context window is 200k, but I’ve noticed that the quality of output clips at the 147k-152k mark. Regardless of which agent is used, when clipping occurs, tool call to
|
|
102
|
+
|
|
103
|
+
Geoffrey Huntley
|
|
104
|
+
Geoffrey Huntley
|
|
105
|
+
|
|
106
|
+
Your task is to implement missing stdlib (see @specs/stdlib/*) and compiler functionality and produce an compiled application in the cursed language via LLVM for that functionality using parrallel subagents. Follow the fix_plan.md and choose the most important thing. Before making changes search codebase (don't assume not implemented) using subagents. You may use up to parrallel subagents for all operations but only 1 subagent for build/tests of rust.
|
|
107
|
+
Another thing to realise is that you can control the amount of parallelism for subagents.
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
0:00
|
|
112
|
+
/0:20
|
|
113
|
+
|
|
114
|
+
1×
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
84 squee (claude subagents) chasing <T>
|
|
118
|
+
|
|
119
|
+
If you were to fan out to a couple of hundred subagents and then tell those subagents to run the build and test of an application, what you'll get is bad form back pressure. Thus, the instruction above is that only a single subagent should be used for validation, but Ralph can use as many subagents as he likes for searching the file system and for writing files.
|
|
120
|
+
|
|
121
|
+
don't assume it's not implemented
|
|
122
|
+
The way that all these coding agents work is via ripgrep, and it's essential to understand that code-based search can be non-deterministic.
|
|
123
|
+
|
|
124
|
+
from Luddites to AI: the Overton Window of disruption
|
|
125
|
+
I’ve been thinking about Overton Windows lately, but not of the political variety. You see, the Overton window can be adapted to model disruptive innovation by framing the acceptance of novel technologies, business models, or ideas within a market or society. So I’ve been pondering about where, when and how
|
|
126
|
+
|
|
127
|
+
Geoffrey Huntley
|
|
128
|
+
Geoffrey Huntley
|
|
129
|
+
|
|
130
|
+
A common failure scenario for Ralph is when the LLM runs ripgrep and comes to the incorrect conclusion that the code has not been implemented. This failure scenario is easily resolved by erecting a sign for Ralph, instructing Ralph not to make assumptions.
|
|
131
|
+
|
|
132
|
+
Before making changes search codebase (don't assume an item is not implemented) using parrallel subagents. Think hard.
|
|
133
|
+
If you wake up to find that Ralph is doing multiple implementations, then you need to tune this step. This nondeterminism is the Achilles' heel of Ralph.
|
|
134
|
+
|
|
135
|
+
phase one: generate
|
|
136
|
+
Generating code is now cheap, and the code that Ralph generates is within your complete control through your technical standard library and your specifications.
|
|
137
|
+
|
|
138
|
+
From Design doc to code: the Groundhog AI coding assistant (and new Cursor vibecoding meta)
|
|
139
|
+
Ello everyone, in the “Yes, Claude Code can decompile itself. Here’s the source code” blog post, I teased about a new meta when using Cursor. This post is a follow-up to the post below. You are using Cursor AI incorrectly...I’m hesitant to give this advice away for free,
|
|
140
|
+
|
|
141
|
+
Geoffrey Huntley
|
|
142
|
+
Geoffrey Huntley
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
You are using Cursor AI incorrectly...
|
|
146
|
+
🗞️I recently shipped a follow-up blog post to this one; this post remains true. You’ll need to know this to be able to drive the N-factor of weeks of co-worker output in hours technique as detailed at https://ghuntley.com/specs I’m hesitant to give this advice away for free,
|
|
147
|
+
|
|
148
|
+
Geoffrey Huntley
|
|
149
|
+
Geoffrey Huntley
|
|
150
|
+
|
|
151
|
+
If Ralph is generating the wrong code or using the wrong technical patterns, then you should update your standard library to steer it to use the correct patterns.
|
|
152
|
+
|
|
153
|
+
If Ralph is building the wrong thing completely, then your specifications may be incorrect. A big, hard lesson for me when building CURSED was that it was only a month in that I noticed that my specification for the lexer defined a keyword twice for two opposing scenarios, which resulted in a lot of time wasted. Ralph was doing stupid shit, and I guess it's easy to blame the tools instead of the operator.
|
|
154
|
+
|
|
155
|
+
phase two: backpressure
|
|
156
|
+
|
|
157
|
+
This is where you need to have your engineering hat on. As code generation is easy now, what is hard is ensuring that Ralph has generated the right thing. Specific programming languages have inbuilt back pressure through their type system.
|
|
158
|
+
|
|
159
|
+
Now you might be thinking, "Rust! It's got the best type system." However, one thing with Rust is that the compilation speed is slow. It's the speed of the wheel turning that matters, balanced against the axis of correctness.
|
|
160
|
+
|
|
161
|
+
Which language to use requires experimentation. As I'm creating a compiler, I wanted extreme correctness, which meant using Rust; however, this approach means it's built more slowly. These LLMs are not very good at generating the perfect Rust code in one attempt, which means they need to make more attempts.
|
|
162
|
+
|
|
163
|
+
That can be either a positive or a negative thing.
|
|
164
|
+
|
|
165
|
+
In the diagram above, it just shows the words "test and build", but this is where you put your engineering hat on. Anything can be wired in as back pressure to reject invalid code generation. That could be security scanners, it could be static analysers, it could be anything. But the key collective sum is that the wheel has got to turn fast.
|
|
166
|
+
|
|
167
|
+
A staple when building CURSED has been the following prompt. After making a change, run a test just for that unit of code that was implemented and improved.
|
|
168
|
+
|
|
169
|
+
After implementing functionality or resolving problems, run the tests for that unit of code that was improved.
|
|
170
|
+
If you're using a dynamically typed language, I must stress the importance of wiring in a static analyser/type checker when Ralphing, such as:
|
|
171
|
+
|
|
172
|
+
https://www.erlang.org/doc/apps/dialyzer/dialyzer.html
|
|
173
|
+
https://pyrefly.org/
|
|
174
|
+
If you do not, then you will run into a bonfire of outcomes.
|
|
175
|
+
|
|
176
|
+
capture the importance of tests in the moment
|
|
177
|
+
When you instruct Ralph to write tests as a form of back pressure, because we are writing Ralph doing one thing and one thing only, every loop, with each loop with its new context window, it's crucial in that moment to ask Ralph to write out the meaning and the importance of the test explaining what it's trying to do.
|
|
178
|
+
|
|
179
|
+
Important: When authoring documentation (ie. rust doc or cursed stdlib documentation) capture the why tests and the backing implementation is important.
|
|
180
|
+
In implementation, it looks similar to this. To me, I see it like leaving little notes for future iterations by the LLM, explaining why a test exists and its importance because future loops will not have the reasoning in their context window.
|
|
181
|
+
|
|
182
|
+
defmodule Anole.Database.QueryOptimizerTest do
|
|
183
|
+
@moduledoc """
|
|
184
|
+
Tests for the database query optimizer.
|
|
185
|
+
|
|
186
|
+
These tests verify the functionality of the QueryOptimizer module, ensuring that
|
|
187
|
+
it correctly implements caching, batching, and analysis of database queries to
|
|
188
|
+
improve performance.
|
|
189
|
+
|
|
190
|
+
The tests use both real database calls and mocks to ensure comprehensive coverage
|
|
191
|
+
while maintaining test isolation and reliability.
|
|
192
|
+
"""
|
|
193
|
+
|
|
194
|
+
use Anole.DataCase
|
|
195
|
+
|
|
196
|
+
import ExUnit.CaptureLog
|
|
197
|
+
import Ecto.Query
|
|
198
|
+
import Mock
|
|
199
|
+
|
|
200
|
+
alias Anole.Database.QueryOptimizer
|
|
201
|
+
alias Anole.Repo
|
|
202
|
+
alias Anole.Tenant.Isolator
|
|
203
|
+
alias Anole.Test.Factory
|
|
204
|
+
|
|
205
|
+
# Set up the test environment with a tenant context
|
|
206
|
+
setup do
|
|
207
|
+
# Create a tenant for isolation testing
|
|
208
|
+
tenant = Factory.insert(:tenant)
|
|
209
|
+
|
|
210
|
+
# Ensure the optimizer is initialized
|
|
211
|
+
QueryOptimizer.init()
|
|
212
|
+
|
|
213
|
+
# Return context
|
|
214
|
+
{:ok, %{tenant: tenant}}
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
describe "init/0" do
|
|
218
|
+
@doc """
|
|
219
|
+
Tests that the QueryOptimizer initializes the required ETS tables.
|
|
220
|
+
|
|
221
|
+
This test ensures that the init function properly creates the ETS tables
|
|
222
|
+
needed for caching and statistics tracking. This is fundamental to the
|
|
223
|
+
module's operation.
|
|
224
|
+
"""
|
|
225
|
+
test "creates required ETS tables" do
|
|
226
|
+
# Clean up any existing tables first
|
|
227
|
+
try do :ets.delete(:anole_query_cache) catch _:_ -> :ok end
|
|
228
|
+
try do :ets.delete(:anole_query_stats) catch _:_ -> :ok end
|
|
229
|
+
|
|
230
|
+
# Call init
|
|
231
|
+
assert :ok = QueryOptimizer.init()
|
|
232
|
+
|
|
233
|
+
# Verify tables exist
|
|
234
|
+
assert :ets.info(:anole_query_cache) != :undefined
|
|
235
|
+
assert :ets.info(:anole_query_stats) != :undefined
|
|
236
|
+
|
|
237
|
+
# Verify table properties
|
|
238
|
+
assert :ets.info(:anole_query_cache, :type) == :set
|
|
239
|
+
assert :ets.info(:anole_query_stats, :type) == :set
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
I've found that it helps the LLMs decide if a test is no longer relevant or if the test is important, and it affects the decision-making whether to delete, modify or resolve a test [failure].
|
|
243
|
+
|
|
244
|
+
no cheating
|
|
245
|
+
Claude has the inherent bias to do minimal and placeholder implementations. So, at various stages in the development of CURSED, I've brought in a variation of this prompt.
|
|
246
|
+
|
|
247
|
+
After implementing functionality or resolving problems, run the tests for that unit of code that was improved. If functionality is missing then it's your job to add it as per the application specifications. Think hard.
|
|
248
|
+
|
|
249
|
+
If tests unrelated to your work fail then it's your job to resolve these tests as part of the increment of change.
|
|
250
|
+
|
|
251
|
+
9999999999999999999999999999. DO NOT IMPLEMENT PLACEHOLDER OR SIMPLE IMPLEMENTATIONS. WE WANT FULL IMPLEMENTATIONS. DO IT OR I WILL YELL AT YOU
|
|
252
|
+
Do not be dismayed if, in the early days, Ralph ignores this sign and does placeholder implementations. The models have been trained to chase their reward function, and the reward function is compiling code. You can always run more Ralphs to identify placeholders and minimal implementations and transform that into a to-do list for future Ralph loops.
|
|
253
|
+
|
|
254
|
+
the todo list
|
|
255
|
+
Speaking of which, here is the prompt stack I've been using over the last couple of weeks to build the TODO list. This is the part where I say Ralph will test you. You have to believe in eventual consistency and know that most issues can be resolved through more loops with Ralph, focusing on the areas where Ralph is making mistakes.
|
|
256
|
+
|
|
257
|
+
study specs/* to learn about the compiler specifications and fix_plan.md to understand plan so far.
|
|
258
|
+
|
|
259
|
+
The source code of the compiler is in src/*
|
|
260
|
+
|
|
261
|
+
The source code of the examples is in examples/* and the source code of the tree-sitter is in tree-sitter/*. Study them.
|
|
262
|
+
|
|
263
|
+
The source code of the stdlib is in src/stdlib/*. Study them.
|
|
264
|
+
|
|
265
|
+
First task is to study @fix_plan.md (it may be incorrect) and is to use up to 500 subagents to study existing source code in src/ and compare it against the compiler specifications. From that create/update a @fix_plan.md which is a bullet point list sorted in priority of the items which have yet to be implemeneted. Think extra hard and use the oracle to plan. Consider searching for TODO, minimal implementations and placeholders. Study @fix_plan.md to determine starting point for research and keep it up to date with items considered complete/incomplete using subagents.
|
|
266
|
+
|
|
267
|
+
Second task is to use up to 500 subagents to study existing source code in examples/ then compare it against the compiler specifications. From that create/update a fix_plan.md which is a bullet point list sorted in priority of the items which have yet to be implemeneted. Think extra hard and use the oracle to plan. Consider searching for TODO, minimal implementations and placeholders. Study fix_plan.md to determine starting point for research and keep it up to date with items considered complete/incomplete.
|
|
268
|
+
|
|
269
|
+
IMPORTANT: The standard library in src/stdlib should be built in cursed itself, not rust. If you find stdlib authored in rust then it must be noted that it needs to be migrated.
|
|
270
|
+
|
|
271
|
+
ULTIMATE GOAL we want to achieve a self-hosting compiler release with full standard library (stdlib). Consider missing stdlib modules and plan. If the stdlib is missing then author the specification at specs/stdlib/FILENAME.md (do NOT assume that it does not exist, search before creating). The naming of the module should be GenZ named and not conflict with another stdlib module name. If you create a new stdlib module then document the plan to implement in @fix_plan.md
|
|
272
|
+
Eventually, Ralph will run out of things to do in the TODO list. Or, it goes completely off track. It's Ralph Wiggum, after all. It's at this stage where it's a matter of taste. Through building of CURSED, I have deleted the TODO list multiple times. The TODO list is what I'm watching like a hawk. And I throw it out often.
|
|
273
|
+
|
|
274
|
+
Now, if I throw the TODO list out, you might be asking, "Well, how does it know what the next step is?" Well, it's simple. You run a Ralph loop with explicit instructions such as above to generate a new TODO list.
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
Then when you've got your todo list you kick Ralph back off again with... instructions to switch from planning mode to building mode...
|
|
278
|
+
|
|
279
|
+
loop back is everything
|
|
280
|
+
You want to program in ways where Ralph can loop himself back into the LLM for evaluation. This is incredibly important. Always look for opportunities to loop Ralph back on itself. This could be as simple as instructing it to add additional logging, or in the case of a compiler, asking Ralph to compile the application and then looking at the LLVM IR representation.
|
|
281
|
+
|
|
282
|
+
You may add extra logging if required to be able to debug the issues.
|
|
283
|
+
ralph can take himself to university
|
|
284
|
+
The @AGENT.md is the heart of the loop. It instructs how Ralph should compile and run the project. If Ralph discovers a learning, permit him to self-improve:
|
|
285
|
+
|
|
286
|
+
When you learn something new about how to run the compiler or examples make sure you update @AGENT.md using a subagent but keep it brief. For example if you run commands multiple times before learning the correct command then that file should be updated.
|
|
287
|
+
During a loop, Ralph might determine that something needs to be fixed. It's crucial to capture that reasoning.
|
|
288
|
+
|
|
289
|
+
For any bugs you notice, it's important to resolve them or document them in @fix_plan.md to be resolved using a subagent even if it is unrelated to the current piece of work after documenting it in @fix_plan.md
|
|
290
|
+
you will wake up to a broken code base
|
|
291
|
+
Yep, it's true, you'll wake up to a broken codebase that doesn't compile from time to time, and you'll have situations where Ralph can't fix it himself. This is where you need to put your brain on. You need to make a judgment call. Is it easier to do a git reset --hard and to kick Ralph back off again? Or do you need to come up with another series of prompts to be able to rescue Ralph?
|
|
292
|
+
|
|
293
|
+
When the tests pass update the @fix_plan.md`, then add changed code and @fix_plan.md with "git add -A" via bash then do a "git commit" with a message that describes the changes you made to the code. After the commit do a "git push" to push the changes to the remote repository.
|
|
294
|
+
|
|
295
|
+
As soon as there are no build or test errors create a git tag. If there are no git tags start at 0.0.0 and increment patch by 1 for example 0.0.1 if 0.0.0 does not exist.
|
|
296
|
+
I recall when I was first getting this compiler up and running, and the number of compilation errors was so large that it filled Claude's context window. So, at that point, I took the file of compilation errors and threw it into Gemini, asking Gemini to create a plan for Ralph.
|
|
297
|
+
|
|
298
|
+
but maintainability?
|
|
299
|
+
When I hear that argument, I question “by whom”? By humans? Why are humans the frame for maintainability? Aren’t we in the post-AI phase where you can just run loops to resolve/adapt when needed? 😎
|
|
300
|
+
|
|
301
|
+
any problem created by AI can be resolved through a different series of prompts
|
|
302
|
+
Which brings me to this point. If you wanted to be cheeky, you could probably find the codebase for CURSED on GitHub. I ask that you refrain from sharing it on social media, as it's not yet ready for launch. I want to dial this thing in so much that we have indisputable proof that AI can build a brand new programming language and program a programming language where it has no training data in its training set is possible.
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
cursed as a webserver
|
|
306
|
+
What I'd like people to understand is that all these issues, created by Ralph, can be resolved by crafting a different series of prompts and running more loops with Ralph.
|
|
307
|
+
|
|
308
|
+
I'm expecting CURSED to have some significant gaps, just like Ralph Wiggum. It'd be so easy for people to poke holes in CURSED, as it is right now, which is why I have been holding off on publishing this post. The repository is full of garbage, temporary files, and binaries.
|
|
309
|
+
|
|
310
|
+
Ralph has three states. Under baked, baked, or baked with unspecified latent behaviours (which are sometimes quite nice!)
|
|
311
|
+
When CURSED ships, understand that Ralph built it. What comes next, technique-wise, won’t be Ralph. I firmly maintain that if models and tools remain as they are now, we are in post-AGI territory. All you need are tokens; these models yearn for tokens, so throw them at them, and you have primitives to automate software development if you take the right approaches.
|
|
312
|
+
|
|
313
|
+
Having said all of that, engineers are still needed. There is no way this is possible without senior expertise guiding Ralph. Anyone claiming that engineers are no longer required and a tool can do 100% of the work without an engineer is peddling horseshit.
|
|
314
|
+
|
|
315
|
+
However, the Ralph technique is surprisingly effective enough to displace a large majority of SWEs as they are currently for Greenfield projects.
|
|
316
|
+
|
|
317
|
+
As a final closing remark, I'll say,
|
|
318
|
+
|
|
319
|
+
"There's no way in heck would I use Ralph in an existing code base"
|
|
320
|
+
though, if you try, I'd be interested in hearing what your outcomes are. This works best as a technique for bootstrapping Greenfield, with the expectation you'll get 90% done with it.
|
|
321
|
+
|
|
322
|
+
current prompt used to build cursed
|
|
323
|
+
Here's the current prompt used by Ralph to build CURSED.
|
|
324
|
+
|
|
325
|
+
0a. study specs/* to learn about the compiler specifications
|
|
326
|
+
|
|
327
|
+
0b. The source code of the compiler is in src/
|
|
328
|
+
|
|
329
|
+
0c. study fix_plan.md.
|
|
330
|
+
|
|
331
|
+
1. Your task is to implement missing stdlib (see @specs/stdlib/*) and compiler functionality and produce an compiled application in the cursed language via LLVM for that functionality using parrallel subagents. Follow the fix_plan.md and choose the most important 10 things. Before making changes search codebase (don't assume not implemented) using subagents. You may use up to 500 parrallel subagents for all operations but only 1 subagent for build/tests of rust.
|
|
332
|
+
|
|
333
|
+
2. After implementing functionality or resolving problems, run the tests for that unit of code that was improved. If functionality is missing then it's your job to add it as per the application specifications. Think hard.
|
|
334
|
+
|
|
335
|
+
2. When you discover a parser, lexer, control flow or LLVM issue. Immediately update @fix_plan.md with your findings using a subagent. When the issue is resolved, update @fix_plan.md and remove the item using a subagent.
|
|
336
|
+
|
|
337
|
+
3. When the tests pass update the @fix_plan.md`, then add changed code and @fix_plan.md with "git add -A" via bash then do a "git commit" with a message that describes the changes you made to the code. After the commit do a "git push" to push the changes to the remote repository.
|
|
338
|
+
|
|
339
|
+
999. Important: When authoring documentation (ie. rust doc or cursed stdlib documentation) capture the why tests and the backing implementation is important.
|
|
340
|
+
|
|
341
|
+
9999. Important: We want single sources of truth, no migrations/adapters. If tests unrelated to your work fail then it's your job to resolve these tests as part of the increment of change.
|
|
342
|
+
|
|
343
|
+
999999. As soon as there are no build or test errors create a git tag. If there are no git tags start at 0.0.0 and increment patch by 1 for example 0.0.1 if 0.0.0 does not exist.
|
|
344
|
+
|
|
345
|
+
999999999. You may add extra logging if required to be able to debug the issues.
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
9999999999. ALWAYS KEEP @fix_plan.md up to do date with your learnings using a subagent. Especially after wrapping up/finishing your turn.
|
|
349
|
+
|
|
350
|
+
99999999999. When you learn something new about how to run the compiler or examples make sure you update @AGENT.md using a subagent but keep it brief. For example if you run commands multiple times before learning the correct command then that file should be updated.
|
|
351
|
+
|
|
352
|
+
999999999999. IMPORTANT DO NOT IGNORE: The standard libray should be authored in cursed itself and tests authored. If you find rust implementation then delete it/migrate to implementation in the cursed language.
|
|
353
|
+
|
|
354
|
+
99999999999999. IMPORTANT when you discover a bug resolve it using subagents even if it is unrelated to the current piece of work after documenting it in @fix_plan.md
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
9999999999999999. When you start implementing the standard library (stdlib) in the cursed language, start with the testing primitives so that future standard library in the cursed language can be tested.
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
99999999999999999. The tests for the cursed standard library "stdlib" should be located in the folder of the stdlib library next to the source code. Ensure you document the stdlib library with a README.md in the same folder as the source code.
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
9999999999999999999. Keep AGENT.md up to date with information on how to build the compiler and your learnings to optimise the build/test loop using a subagent.
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
999999999999999999999. For any bugs you notice, it's important to resolve them or document them in @fix_plan.md to be resolved using a subagent.
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
99999999999999999999999. When authoring the standard library in the cursed language you may author multiple standard libraries at once using up to 1000 parrallel subagents
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
99999999999999999999999999. When @fix_plan.md becomes large periodically clean out the items that are completed from the file using a subagent.
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
99999999999999999999999999. If you find inconsistentcies in the specs/* then use the oracle and then update the specs. Specifically around types and lexical tokens.
|
|
376
|
+
|
|
377
|
+
9999999999999999999999999999. DO NOT IMPLEMENT PLACEHOLDER OR SIMPLE IMPLEMENTATIONS. WE WANT FULL IMPLEMENTATIONS. DO IT OR I WILL YELL AT YOU
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
9999999999999999999999999999999. SUPER IMPORTANT DO NOT IGNORE. DO NOT PLACE STATUS REPORT UPDATES INTO @AGENT.md
|
|
381
|
+
current prompt used to plan cursed
|
|
382
|
+
study specs/* to learn about the compiler specifications and fix_plan.md to understand plan so far.
|
|
383
|
+
|
|
384
|
+
The source code of the compiler is in src/*
|
|
385
|
+
|
|
386
|
+
The source code of the examples is in examples/* and the source code of the tree-sitter is in tree-sitter/*. Study them.
|
|
387
|
+
|
|
388
|
+
The source code of the stdlib is in src/stdlib/*. Study them.
|
|
389
|
+
|
|
390
|
+
First task is to study @fix_plan.md (it may be incorrect) and is to use up to 500 subagents to study existing source code in src/ and compare it against the compiler specifications. From that create/update a @fix_plan.md which is a bullet point list sorted in priority of the items which have yet to be implemeneted. Think extra hard and use the oracle to plan. Consider searching for TODO, minimal implementations and placeholders. Study @fix_plan.md to determine starting point for research and keep it up to date with items considered complete/incomplete using subagents.
|
|
391
|
+
|
|
392
|
+
Second task is to use up to 500 subagents to study existing source code in examples/ then compare it against the compiler specifications. From that create/update a fix_plan.md which is a bullet point list sorted in priority of the items which have yet to be implemeneted. Think extra hard and use the oracle to plan. Consider searching for TODO, minimal implementations and placeholders. Study fix_plan.md to determine starting point for research and keep it up to date with items considered complete/incomplete.
|
|
393
|
+
|
|
394
|
+
IMPORTANT: The standard library in src/stdlib should be built in cursed itself, not rust. If you find stdlib authored in rust then it must be noted that it needs to be migrated.
|
|
395
|
+
|
|
396
|
+
ULTIMATE GOAL we want to achieve a self-hosting compiler release with full standard library (stdlib). Consider missing stdlib modules and plan. If the stdlib is missing then author the specification at specs/stdlib/FILENAME.md (do NOT assume that it does not exist, search before creating). The naming of the module should be GenZ named and not conflict with another stdlib module name. If you create a new stdlib module then document the plan to implement in @fix_plan.md
|
|
397
|
+
ps. socials
|
|
398
|
+
X - https://x.com/GeoffreyHuntley/status/1944614322107564194
|
|
399
|
+
LinkedIn - https://www.linkedin.com/posts/geoffreyhuntley_ralph-wiggum-as-a-software-engineer-activity-7350383201233608705-vBRf
|
|
400
|
+
Bsky - https://bsky.app/profile/ghuntley.com/post/3ltvkz6gkh22g
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "ralphify"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Harness toolkit for autonomous AI coding loops"
|
|
5
|
+
requires-python = ">=3.11"
|
|
6
|
+
dependencies = ["typer>=0.9", "rich>=13.0"]
|
|
7
|
+
|
|
8
|
+
[project.scripts]
|
|
9
|
+
ralph = "ralphify:main"
|
|
10
|
+
|
|
11
|
+
[build-system]
|
|
12
|
+
requires = ["hatchling"]
|
|
13
|
+
build-backend = "hatchling.build"
|
|
14
|
+
|
|
15
|
+
[tool.hatch.build.targets.wheel]
|
|
16
|
+
packages = ["src/ralphify"]
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
import sys
|
|
3
|
+
import tomllib
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
from rich import print as rprint
|
|
9
|
+
|
|
10
|
+
from ralphify.detector import detect_project
|
|
11
|
+
|
|
12
|
+
app = typer.Typer(help="Harness toolkit for autonomous AI coding loops.")
|
|
13
|
+
|
|
14
|
+
CONFIG_FILENAME = "ralph.toml"
|
|
15
|
+
|
|
16
|
+
RALPH_TOML_TEMPLATE = """\
|
|
17
|
+
[agent]
|
|
18
|
+
command = "claude"
|
|
19
|
+
args = ["-p", "--dangerously-skip-permissions"]
|
|
20
|
+
prompt = "PROMPT.md"
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
PROMPT_TEMPLATE = """\
|
|
24
|
+
# Prompt
|
|
25
|
+
|
|
26
|
+
You are an autonomous coding agent running in a loop. Each iteration
|
|
27
|
+
starts with a fresh context. Your progress lives in the code and git.
|
|
28
|
+
|
|
29
|
+
- Implement one thing per iteration
|
|
30
|
+
- Search before creating anything new
|
|
31
|
+
- No placeholder code — full implementations only
|
|
32
|
+
- Run tests and fix failures before committing
|
|
33
|
+
- Commit with a descriptive message
|
|
34
|
+
|
|
35
|
+
<!-- Add your project-specific instructions below -->
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@app.command()
|
|
40
|
+
def init(
|
|
41
|
+
force: bool = typer.Option(False, "--force", "-f", help="Overwrite existing files."),
|
|
42
|
+
) -> None:
|
|
43
|
+
"""Initialize ralph config and prompt template."""
|
|
44
|
+
config_path = Path(CONFIG_FILENAME)
|
|
45
|
+
prompt_path = Path("PROMPT.md")
|
|
46
|
+
|
|
47
|
+
project_type = detect_project()
|
|
48
|
+
|
|
49
|
+
if config_path.exists() and not force:
|
|
50
|
+
rprint(f"[yellow]{CONFIG_FILENAME} already exists. Use --force to overwrite.[/yellow]")
|
|
51
|
+
raise typer.Exit(1)
|
|
52
|
+
|
|
53
|
+
config_path.write_text(RALPH_TOML_TEMPLATE)
|
|
54
|
+
rprint(f"[green]Created {CONFIG_FILENAME}[/green]")
|
|
55
|
+
|
|
56
|
+
if prompt_path.exists() and not force:
|
|
57
|
+
rprint(f"[yellow]PROMPT.md already exists. Use --force to overwrite.[/yellow]")
|
|
58
|
+
else:
|
|
59
|
+
prompt_path.write_text(PROMPT_TEMPLATE)
|
|
60
|
+
rprint(f"[green]Created PROMPT.md[/green]")
|
|
61
|
+
|
|
62
|
+
rprint(f"\nDetected project type: [bold]{project_type}[/bold]")
|
|
63
|
+
rprint("Edit PROMPT.md to customize your agent's behavior.")
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@app.command()
|
|
67
|
+
def run(
|
|
68
|
+
n: Optional[int] = typer.Option(None, "-n", help="Max number of iterations. Infinite if not set."),
|
|
69
|
+
) -> None:
|
|
70
|
+
"""Run the autonomous coding loop."""
|
|
71
|
+
config_path = Path(CONFIG_FILENAME)
|
|
72
|
+
|
|
73
|
+
if not config_path.exists():
|
|
74
|
+
rprint(f"[red]{CONFIG_FILENAME} not found. Run 'ralph init' first.[/red]")
|
|
75
|
+
raise typer.Exit(1)
|
|
76
|
+
|
|
77
|
+
with open(config_path, "rb") as f:
|
|
78
|
+
config = tomllib.load(f)
|
|
79
|
+
|
|
80
|
+
agent = config["agent"]
|
|
81
|
+
command = agent["command"]
|
|
82
|
+
args = agent.get("args", [])
|
|
83
|
+
prompt_file = agent["prompt"]
|
|
84
|
+
|
|
85
|
+
prompt_path = Path(prompt_file)
|
|
86
|
+
if not prompt_path.exists():
|
|
87
|
+
rprint(f"[red]Prompt file '{prompt_file}' not found.[/red]")
|
|
88
|
+
raise typer.Exit(1)
|
|
89
|
+
|
|
90
|
+
cmd = [command] + args
|
|
91
|
+
iteration = 0
|
|
92
|
+
|
|
93
|
+
try:
|
|
94
|
+
while True:
|
|
95
|
+
iteration += 1
|
|
96
|
+
if n is not None and iteration > n:
|
|
97
|
+
break
|
|
98
|
+
|
|
99
|
+
rprint(f"\n[bold blue]── Iteration {iteration} ──[/bold blue]")
|
|
100
|
+
prompt = prompt_path.read_text()
|
|
101
|
+
subprocess.run(cmd, input=prompt, text=True)
|
|
102
|
+
|
|
103
|
+
except KeyboardInterrupt:
|
|
104
|
+
pass
|
|
105
|
+
|
|
106
|
+
rprint(f"\n[green]Completed {iteration if n is None else min(iteration, n)} iteration(s).[/green]")
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def detect_project(path: Path = Path(".")) -> str:
|
|
5
|
+
"""Detect project type based on manifest files."""
|
|
6
|
+
markers = {
|
|
7
|
+
"package.json": "node",
|
|
8
|
+
"pyproject.toml": "python",
|
|
9
|
+
"Cargo.toml": "rust",
|
|
10
|
+
"go.mod": "go",
|
|
11
|
+
}
|
|
12
|
+
for filename, project_type in markers.items():
|
|
13
|
+
if (path / filename).exists():
|
|
14
|
+
return project_type
|
|
15
|
+
return "generic"
|
ralphify-0.1.0/uv.lock
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
version = 1
|
|
2
|
+
revision = 3
|
|
3
|
+
requires-python = ">=3.11"
|
|
4
|
+
|
|
5
|
+
[[package]]
|
|
6
|
+
name = "annotated-doc"
|
|
7
|
+
version = "0.0.4"
|
|
8
|
+
source = { registry = "https://pypi.org/simple" }
|
|
9
|
+
sdist = { url = "https://files.pythonhosted.org/packages/57/ba/046ceea27344560984e26a590f90bc7f4a75b06701f653222458922b558c/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4", size = 7288, upload-time = "2025-11-10T22:07:42.062Z" }
|
|
10
|
+
wheels = [
|
|
11
|
+
{ url = "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320", size = 5303, upload-time = "2025-11-10T22:07:40.673Z" },
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
[[package]]
|
|
15
|
+
name = "click"
|
|
16
|
+
version = "8.3.1"
|
|
17
|
+
source = { registry = "https://pypi.org/simple" }
|
|
18
|
+
dependencies = [
|
|
19
|
+
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
|
20
|
+
]
|
|
21
|
+
sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" }
|
|
22
|
+
wheels = [
|
|
23
|
+
{ url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" },
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[[package]]
|
|
27
|
+
name = "colorama"
|
|
28
|
+
version = "0.4.6"
|
|
29
|
+
source = { registry = "https://pypi.org/simple" }
|
|
30
|
+
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
|
|
31
|
+
wheels = [
|
|
32
|
+
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[[package]]
|
|
36
|
+
name = "markdown-it-py"
|
|
37
|
+
version = "4.0.0"
|
|
38
|
+
source = { registry = "https://pypi.org/simple" }
|
|
39
|
+
dependencies = [
|
|
40
|
+
{ name = "mdurl" },
|
|
41
|
+
]
|
|
42
|
+
sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" }
|
|
43
|
+
wheels = [
|
|
44
|
+
{ url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" },
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
[[package]]
|
|
48
|
+
name = "mdurl"
|
|
49
|
+
version = "0.1.2"
|
|
50
|
+
source = { registry = "https://pypi.org/simple" }
|
|
51
|
+
sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" }
|
|
52
|
+
wheels = [
|
|
53
|
+
{ url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
[[package]]
|
|
57
|
+
name = "pygments"
|
|
58
|
+
version = "2.19.2"
|
|
59
|
+
source = { registry = "https://pypi.org/simple" }
|
|
60
|
+
sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" }
|
|
61
|
+
wheels = [
|
|
62
|
+
{ url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
[[package]]
|
|
66
|
+
name = "ralphify"
|
|
67
|
+
version = "0.1.0"
|
|
68
|
+
source = { editable = "." }
|
|
69
|
+
dependencies = [
|
|
70
|
+
{ name = "rich" },
|
|
71
|
+
{ name = "typer" },
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
[package.metadata]
|
|
75
|
+
requires-dist = [
|
|
76
|
+
{ name = "rich", specifier = ">=13.0" },
|
|
77
|
+
{ name = "typer", specifier = ">=0.9" },
|
|
78
|
+
]
|
|
79
|
+
|
|
80
|
+
[[package]]
|
|
81
|
+
name = "rich"
|
|
82
|
+
version = "14.3.3"
|
|
83
|
+
source = { registry = "https://pypi.org/simple" }
|
|
84
|
+
dependencies = [
|
|
85
|
+
{ name = "markdown-it-py" },
|
|
86
|
+
{ name = "pygments" },
|
|
87
|
+
]
|
|
88
|
+
sdist = { url = "https://files.pythonhosted.org/packages/b3/c6/f3b320c27991c46f43ee9d856302c70dc2d0fb2dba4842ff739d5f46b393/rich-14.3.3.tar.gz", hash = "sha256:b8daa0b9e4eef54dd8cf7c86c03713f53241884e814f4e2f5fb342fe520f639b", size = 230582, upload-time = "2026-02-19T17:23:12.474Z" }
|
|
89
|
+
wheels = [
|
|
90
|
+
{ url = "https://files.pythonhosted.org/packages/14/25/b208c5683343959b670dc001595f2f3737e051da617f66c31f7c4fa93abc/rich-14.3.3-py3-none-any.whl", hash = "sha256:793431c1f8619afa7d3b52b2cdec859562b950ea0d4b6b505397612db8d5362d", size = 310458, upload-time = "2026-02-19T17:23:13.732Z" },
|
|
91
|
+
]
|
|
92
|
+
|
|
93
|
+
[[package]]
|
|
94
|
+
name = "shellingham"
|
|
95
|
+
version = "1.5.4"
|
|
96
|
+
source = { registry = "https://pypi.org/simple" }
|
|
97
|
+
sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" }
|
|
98
|
+
wheels = [
|
|
99
|
+
{ url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" },
|
|
100
|
+
]
|
|
101
|
+
|
|
102
|
+
[[package]]
|
|
103
|
+
name = "typer"
|
|
104
|
+
version = "0.24.1"
|
|
105
|
+
source = { registry = "https://pypi.org/simple" }
|
|
106
|
+
dependencies = [
|
|
107
|
+
{ name = "annotated-doc" },
|
|
108
|
+
{ name = "click" },
|
|
109
|
+
{ name = "rich" },
|
|
110
|
+
{ name = "shellingham" },
|
|
111
|
+
]
|
|
112
|
+
sdist = { url = "https://files.pythonhosted.org/packages/f5/24/cb09efec5cc954f7f9b930bf8279447d24618bb6758d4f6adf2574c41780/typer-0.24.1.tar.gz", hash = "sha256:e39b4732d65fbdcde189ae76cf7cd48aeae72919dea1fdfc16593be016256b45", size = 118613, upload-time = "2026-02-21T16:54:40.609Z" }
|
|
113
|
+
wheels = [
|
|
114
|
+
{ url = "https://files.pythonhosted.org/packages/4a/91/48db081e7a63bb37284f9fbcefda7c44c277b18b0e13fbc36ea2335b71e6/typer-0.24.1-py3-none-any.whl", hash = "sha256:112c1f0ce578bfb4cab9ffdabc68f031416ebcc216536611ba21f04e9aa84c9e", size = 56085, upload-time = "2026-02-21T16:54:41.616Z" },
|
|
115
|
+
]
|