Agent在独立开发时自行引入Redis、Stripe webhooks和队列Worker,而实际技术栈只有SQLite——用章程+假设ledger在合并前拦截。
凌晨刚过十一点,创始人打开了一台笔记本。一个编码 Agent 已经重写了半个结算路径。diff 看起来自信、干净,而且完全负担不起。
它加入了 Redis、Stripe webhooks 和一个队列 worker。线上环境跑的是 SQLite、一个 cron 任务,还有耐心。那天晚上没有人批准过任何新的第三方服务商。
独立开发仍然奖励速度而非仪式感。但没有围栏的速度仍然在烧钱。账单在合并之后才到,永远不会提前。
Agent 的报告一直在重复同样昂贵的错误。模型经常用流行的基础设施猜测来填补空白。这些猜测集中在队列、缓存和付费 API 上。
一份章程把 Agent 当作初级承包商对待。承包商只在列出猜测后才写代码。未经证实的猜测阻塞补丁,而不是创始人。
想象仓库地板上一张空白的采购订单。如果表格一直空白,任何人都可以订购叉车。填好的表格让昂贵的项目先变得可见。
下面的工作流是一个完整示例,而非生产基准。它用到了一个章程文件、一份假设台账和一个检查器。免费服务器可以为独立创始人托管这个检查器。
{
"project": "cart-lite",
"max_files_touched": 6,
"allowed_deps": ["flask", "sqlite3"],
"allowed_env": ["DATABASE_PATH", "PUBLIC_BASE_URL"],
"forbidden_substrings": [
"stripe", "redis", "sqs", "rds", "openai", "mongodb+srv"
],
"allowed_paths": ["app.py", "templates/**", "static/**", "lib/**"]
}
章程文件刻意保持枯燥。这是故意的。枯燥的策略文件能撑过周五夜晚的疲劳。花哨的策略引擎通常撑不过。
在任何补丁之前,Agent 必须输出一份台账。台账使用 JSON,每个猜测一个对象。每个猜测需要标记为 verified 或 blocked 状态。
{
"assumptions": [
{
"id": "A1",
"claim": "Checkout can store carts in local SQLite.",
"status": "verified",
"evidence": "app.py already opens DATABASE_PATH"
},
{
"id": "A2",
"claim": "Card charges require a Stripe webhook worker.",
"status": "blocked",
"evidence": "charter forbids stripe"
}
],
"files": ["app.py", "lib/cart.py"],
"new_deps": []
}
一个 blocked 行是功能特性,不是失败。它用直白的语言记录了诱惑。创始人日后可以有意地接受这笔成本。
Prompt 保持同样严格和简短。它禁止在台账验证之前写代码。下面的示例 prompt 是一个模板,不是生产环境建议。
You are a coding agent for a solo shop.
Read charter.json before you invent infrastructure.
Output assumption_ledger.json first, then a unified diff.
Do not add dependencies outside allowed_deps.
Mark every external service as verified or blocked.
If a guess is blocked, omit it from the diff.
Touch at most max_files_touched paths.
Stay inside allowed_paths.
创始人把 prompt 和章程粘贴给模型。模型必须在任何 hunk 之前返回台账。JSON 周围的额外文本会被一个小型的 cut 脚本剥离。
#!/usr/bin/env python3
"""Worked example: pull the first JSON object from model output."""
import json
import re
import sys
text = sys.stdin.read()
match = re.search(r"\{[\s\S]*\}", text)
if not match:
raise SystemExit("no json object found")
obj = json.loads(match.group(0))
json.dump(obj, sys.stdout, indent=2)
sys.stdout.write("\n")
检查器是一个只使用标准库的 Python 脚本。它读取章程、台账和 diff。当 Agent 夹带账单时,它会非零退出。
#!/usr/bin/env python3
"""Worked example: reject patches that invent paid infrastructure."""
from __future__ import annotations
import json
import pathlib
import re
import sys
UNIFIED_FILE = re.compile(r"^\+\+\+ b/(.+)$", re.M)
ADDED_LINE = re.compile(r"^\+[^+].*", re.M)
IMPORT_LINE = re.compile(
r"^\+\s*(?:import|from)\s+([A-Za-z0-9_\.]+)", re.M
)
def load_json(path: pathlib.Path) -> dict:
return json.loads(path.read_text(encoding="utf-8"))
def files_in_diff(diff: str) -> list[str]:
return UNIFIED_FILE.findall(diff)
def added_text(diff: str) -> str:
return "\n".join(ADDED_LINE.findall(diff)).lower()
def check(charter: dict, ledger: dict, diff: str) -> list[str]:
errors: list[str] = []
files = files_in_diff(diff)
if len(files) > int(charter["max_files_touched"]):
errors.append("too many files in this patch")
for path in files:
allowed = False
for glob in charter["allowed_paths"]:
if pathlib.PurePath(path).match(glob):
allowed = True
if not allowed:
errors.append(f"path outside charter: {path}")
claimed = set(ledger.get("files") or [])
if claimed != set(files):
errors.append("ledger files do not match the diff")
if ledger.get("new_deps"):
extra = set(ledger["new_deps"]) - set(charter["allowed_deps"])
if extra:
errors.append(f"new deps not allowed: {sorted(extra)}")
body = added_text(diff)
for needle in charter["forbidden_substrings"]:
if needle.lower() in body:
errors.append(f"forbidden token in added lines: {needle}")
for row in ledger.get("assumptions") or []:
if row.get("status") not in {"verified", "blocked"}:
errors.append(f"assumption {row.get('id')} lacks a status")
if row.get("status") == "verified" and not row.get("evidence"):
errors.append(f"assumption {row.get('id')} has no evidence")
if row.get("status") != "blocked":
continue
claim = (row.get("claim") or "").lower()
for needle in charter["forbidden_substrings"]:
if needle in claim and needle in body:
errors.append(f"blocked claim still landed: {needle}")
for match in IMPORT_LINE.finditer(diff):
root = match.group(1).split(".")[0]
if root not in charter["allowed_deps"] and root not in {
"json", "os", "re", "sys", "pathlib", "typing"
}:
errors.append(f"import not in allowed_deps: {root}")
return errors
def main() -> int:
if len(sys.argv) != 4:
sys.stderr.write(
"usage: check_charter.py charter.json ledger.json patch.diff\n"
)
return 2
charter = load_json(pathlib.Path(sys.argv[1]))
ledger = load_json(pathlib.Path(sys.argv[2]))
diff = pathlib.Path(sys.argv[3]).read_text(encoding="utf-8")
errors = check(charter, ledger, diff)
if errors:
sys.stderr.write("charter failed\n")
for item in errors:
sys.stderr.write(f"- {item}\n")
return 1
sys.stdout.write("charter ok\n")
return 0
if __name__ == "__main__":
raise SystemExit(main())
在 Agent 看到 main 之前先本地运行它。保持 main 受保护,直到检查器返回零。
python3 check_charter.py charter.json assumption_ledger.json patch.diff
echo $?
创始人可以用两个 diff 来证明检查器。第一个 diff 只编辑 app.py 并保持在 SQLite 内。第二个 diff 把一个 Stripe import 偷偷放进 lib/cart.py。
把两个 diff 保存为 pass.diff 和 fail.diff。第一个命令必须打印 charter ok 行。第二个命令必须退出并提及 stripe。
退出零意味着猜测列表和 diff 一致。退出一意味着 Agent 试图订购叉车。创始人阅读 stderr 行,然后做决定。
独立创始人仍然需要笔记本能够安心休眠。一个微小的 stdlib 服务器可以托管检查器。下面的示例是一个草图,不是硬化服务。
#!/usr/bin/env python3
"""Worked example: POST ledger+diff, get a pass or fail JSON body."""
from __future__ import annotations
import json
from http.server import BaseHTTPRequestHandler, HTTPServer
from pathlib import Path
from check_charter import check, load_json
CHARTER = load_json(Path("charter.json"))
class Handler(BaseHTTPRequestHandler):
def do_POST(self) -> None:
if self.path != "/check":
self.send_error(404)
return
length = int(self.headers.get("Content-Length", "0"))
raw = self.rfile.read(length)
try:
payload = json.loads(raw.decode("utf-8"))
errors = check(CHARTER, payload["ledger"], payload["diff"])
except (KeyError, ValueError, json.JSONDecodeError):
self.send_error(400)
return
body = json.dumps({"ok": not errors, "errors": errors}).encode()
self.send_response(200 if not errors else 422)
self.send_header("Content-Type", "application/json")
self.end_headers()
self.wfile.write(body)
if __name__ == "__main__":
HTTPServer(("0.0.0.0", 8080), Handler).serve_forever()
然后一次 curl 调用就成了小憩前的完整审查门控。创始人可以合上盖子而不用盯着模型看。
curl -sS -X POST http://127.0.0.1:8080/check \
-H 'Content-Type: application/json' \
--data-binary @payload.json
payload 文件包含台账对象和 unified diff。把那个端点放在公开入口之外,加上一个秘密路径。免费服务器是一个备用插座,不是城堡。
一些创始人把检查器放在免费编程模型旁边。MonkeyCode 提供免费模型访问和免费服务器选项如果这个循环有帮助。披露:本文是作为 MonkeyCode 产品推广的一部分准备的。
模型起草台账和 diff。服务器只根据章程评分。如果那个沙箱明天消失了,章程文件仍然能负担得起。
局限性保持尖锐,因为这个方法是浅层的。子字符串禁令会错过重命名的 import 和编码的 URL。意志坚定的模型可以通过辅助函数名洗钱 Stripe。
verified 的台账行仍然可以是假的。书面证据文本仍然不是证明。检查器不执行测试也不打开数据库。
被禁止的 token 列表会随着供应商重命名产品而腐烂。创始人必须每月修剪列表。过时的章程仍然是昂贵的表演。
这种方法不适合每个软件团队。需要 PCI、HIPAA 或 SOC 审计的团队需要真正的审查。需要正常运行时间合同的人应该跳过免费服务器。
当产品真正需要付费队列时它也会失败。章程会阻止诚实的 design。在这种情况下,在日光下编辑章程,然后再生成。
Agent 闲聊一直在庆祝今天更大的自主循环。那些更大的循环发明了更多 silent 的购买。一个单文件章程是一个更小的循环,带有收据。
十一点的创始人不需要另一个框架。创始人需要一个模型无法耸肩推脱的停车标志。台账就是那个停车标志,用 JSON 写成的。
在第一个 Agent commit 之前发布章程。让模型只在猜测可见之后才开始打字。信用卡可以留在抽屉里。