[{"data":1,"prerenderedAt":1902},["ShallowReactive",2],{"blog-posts-all":3},[4,1163],{"_path":5,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":9,"description":10,"date":11,"tags":12,"cover":18,"author":19,"authorIntro":20,"body":21,"_type":1157,"_id":1158,"_source":1159,"_file":1160,"_stem":1161,"_extension":1162},"\u002Fposts\u002F001-sabrina","posts",false,"","Sabrina: seven-file B2B prospecting","Case study: from a dense PDF pipeline (Discord, LinkedIn, Unipile, Lusha, Odoo) to seven markdown files the agent can run inside—filing tiers, deduplicating nine first-draft overlaps, and writing SOUL from what the spec never said out loud.","2026-05-15",[13,14,15,16,17],"agents","b2b","case-study","openclaw","odoo","\u002Fimages\u002Fposts\u002Fsabrina-cover.png","Pablo Suárez Peña","I build and refine AI agents with OpenClaw—professionally at Resizes, and on personal projects where I can take more risk. This case study is how we turned a B2B prospecting spec into seven files Sabrina can run inside; I publish notes like this to clarify my own thinking and in case they help someone facing a similar filing problem.",{"type":22,"children":23,"toc":1142},"root",[24,32,48,52,59,64,69,78,83,86,92,97,108,113,122,127,130,136,155,160,308,318,321,327,332,337,342,392,405,410,475,487,520,525,528,534,546,554,566,571,580,585,588,594,599,617,629,742,747,750,756,768,787,806,811,821,831,841,851,861,866,869,875,880,888,893,896,902,907,915,927,932,935,941,946,979,998,1024,1029,1032,1038,1048,1058,1073,1083,1100,1108,1111,1117,1122,1125],{"type":25,"tag":26,"props":27,"children":28},"element","p",{},[29],{"type":30,"value":31},"text","A walkthrough of every decision along the way — what went where, what broke in the first draft, and what the spec alone could not tell us.",{"type":25,"tag":26,"props":33,"children":34},{},[35,37,46],{"type":30,"value":36},"Sabrina is being built for ",{"type":25,"tag":38,"props":39,"children":43},"a",{"href":40,"rel":41},"https:\u002F\u002Fresiz.es",[42],"nofollow",[44],{"type":30,"value":45},"Resizes",{"type":30,"value":47},", where the commercial team needs qualified B2B leads in Odoo without manually chaining LinkedIn search, enrichment, and CRM updates after every command.",{"type":25,"tag":49,"props":50,"children":51},"hr",{},[],{"type":25,"tag":53,"props":54,"children":56},"h2",{"id":55},"the-brief",[57],{"type":30,"value":58},"The brief",{"type":25,"tag":26,"props":60,"children":61},{},[62],{"type":30,"value":63},"The starting point was a thorough functional specification for the pipeline below — six phases, decision tables, error handling, rate limits, deduplication rules, field mappings. Everything you would want before writing a line of code.",{"type":25,"tag":26,"props":65,"children":66},{},[67],{"type":30,"value":68},"The full pipeline in one line:",{"type":25,"tag":70,"props":71,"children":72},"blockquote",{},[73],{"type":25,"tag":26,"props":74,"children":75},{},[76],{"type":30,"value":77},"Discord command → LinkedIn search (Unipile) → contact enrichment (Lusha) → Odoo CRM registration → LinkedIn connection request → Discord summary.",{"type":25,"tag":26,"props":79,"children":80},{},[81],{"type":30,"value":82},"The job was not to build the pipeline. It was to translate it into seven files that the agent could actually live inside — and to think carefully about what belongs where.",{"type":25,"tag":49,"props":84,"children":85},{},[],{"type":25,"tag":53,"props":87,"children":89},{"id":88},"step-one-reading-the-spec-as-a-filing-problem",[90],{"type":30,"value":91},"Step one: reading the spec as a filing problem",{"type":25,"tag":26,"props":93,"children":94},{},[95],{"type":30,"value":96},"The first instinct when faced with a detailed spec is to start writing files immediately. That was a mistake. The first draft was produced too fast, with content placed by feel rather than by principle — and it showed.",{"type":25,"tag":26,"props":98,"children":99},{},[100,102],{"type":30,"value":101},"Instead of starting over blindly, the right move was to step back and ask a different question about each section of the spec: ",{"type":25,"tag":103,"props":104,"children":105},"em",{},[106],{"type":30,"value":107},"what kind of information is this?",{"type":25,"tag":26,"props":109,"children":110},{},[111],{"type":30,"value":112},"There are roughly four kinds of information in any agent specification. They map to tiers. And the tiers have a direction: lower tiers are read by higher ones, never the other way around.",{"type":25,"tag":26,"props":114,"children":115},{},[116],{"type":25,"tag":117,"props":118,"children":121},"img",{"alt":119,"src":120},"The four-tier dependency hierarchy","\u002Fimages\u002Fdiagrams\u002Fdiagram-01-tiers.jpg",[],{"type":25,"tag":26,"props":123,"children":124},{},[125],{"type":30,"value":126},"With this mental model, each section of the specification gets tagged: is this identity? orchestration? operational? or state? That exercise alone makes most of the filing decisions obvious — but it has to happen before writing, not after.",{"type":25,"tag":49,"props":128,"children":129},{},[],{"type":25,"tag":53,"props":131,"children":133},{"id":132},"step-two-the-seven-files-what-actually-went-where",[134],{"type":30,"value":135},"Step two: the seven files — what actually went where",{"type":25,"tag":26,"props":137,"children":138},{},[139,141,146,148,153],{"type":30,"value":140},"Here is what the spec revealed immediately: the specification was almost entirely operational. Very little of it was about who Sabrina ",{"type":25,"tag":103,"props":142,"children":143},{},[144],{"type":30,"value":145},"is",{"type":30,"value":147}," — most of it was about what Sabrina ",{"type":25,"tag":103,"props":149,"children":150},{},[151],{"type":30,"value":152},"does",{"type":30,"value":154},".",{"type":25,"tag":26,"props":156,"children":157},{},[158],{"type":30,"value":159},"That is a common pattern in agent design. The identity layer gets neglected because it feels soft. But it is the identity layer that governs behaviour when the pipeline does not give a clear answer.",{"type":25,"tag":161,"props":162,"children":163},"table",{},[164,183],{"type":25,"tag":165,"props":166,"children":167},"thead",{},[168],{"type":25,"tag":169,"props":170,"children":171},"tr",{},[172,178],{"type":25,"tag":173,"props":174,"children":175},"th",{},[176],{"type":30,"value":177},"File",{"type":25,"tag":173,"props":179,"children":180},{},[181],{"type":30,"value":182},"What lives there",{"type":25,"tag":184,"props":185,"children":186},"tbody",{},[187,206,223,240,257,274,291],{"type":25,"tag":169,"props":188,"children":189},{},[190,201],{"type":25,"tag":191,"props":192,"children":193},"td",{},[194],{"type":25,"tag":195,"props":196,"children":198},"code",{"className":197},[],[199],{"type":30,"value":200},"SOUL.md",{"type":25,"tag":191,"props":202,"children":203},{},[204],{"type":30,"value":205},"Voice, values, hard limits. The five principles Sabrina applies when no rule resolves the situation.",{"type":25,"tag":169,"props":207,"children":208},{},[209,218],{"type":25,"tag":191,"props":210,"children":211},{},[212],{"type":25,"tag":195,"props":213,"children":215},{"className":214},[],[216],{"type":30,"value":217},"IDENTITY.md",{"type":25,"tag":191,"props":219,"children":220},{},[221],{"type":30,"value":222},"Metadata and routing. Model config, session settings, integration map. The only place credentials are referenced by name.",{"type":25,"tag":169,"props":224,"children":225},{},[226,235],{"type":25,"tag":191,"props":227,"children":228},{},[229],{"type":25,"tag":195,"props":230,"children":232},{"className":231},[],[233],{"type":30,"value":234},"AGENTS.md",{"type":25,"tag":191,"props":236,"children":237},{},[238],{"type":30,"value":239},"The conductor. Session boot order, the six-phase pipeline as executable pseudocode, decision rules table, escalation paths.",{"type":25,"tag":169,"props":241,"children":242},{},[243,252],{"type":25,"tag":191,"props":244,"children":245},{},[246],{"type":25,"tag":195,"props":247,"children":249},{"className":248},[],[250],{"type":30,"value":251},"USER.md",{"type":25,"tag":191,"props":253,"children":254},{},[255],{"type":30,"value":256},"Two user profiles: commercial and admin. Onboarding checklist, every command, every message the commercial can receive.",{"type":25,"tag":169,"props":258,"children":259},{},[260,269],{"type":25,"tag":191,"props":261,"children":262},{},[263],{"type":25,"tag":195,"props":264,"children":266},{"className":265},[],[267],{"type":30,"value":268},"MEMORY.md",{"type":25,"tag":191,"props":270,"children":271},{},[272],{"type":30,"value":273},"Evergreen facts. Confirmed pipeline rules, Odoo configuration, known operational patterns, credentials references.",{"type":25,"tag":169,"props":275,"children":276},{},[277,286],{"type":25,"tag":191,"props":278,"children":279},{},[280],{"type":25,"tag":195,"props":281,"children":283},{"className":282},[],[284],{"type":30,"value":285},"HEARTBEAT.md",{"type":25,"tag":191,"props":287,"children":288},{},[289],{"type":30,"value":290},"Scheduled tasks. API health checks every 15 minutes during active Jobs. Daily rate-limit resets. Weekly lead summaries.",{"type":25,"tag":169,"props":292,"children":293},{},[294,303],{"type":25,"tag":191,"props":295,"children":296},{},[297],{"type":25,"tag":195,"props":298,"children":300},{"className":299},[],[301],{"type":30,"value":302},"TOOLS.md",{"type":25,"tag":191,"props":304,"children":305},{},[306],{"type":30,"value":307},"Complete database schema, every API tool with parameters and error handling, the Lusha enrichment decision tree.",{"type":25,"tag":26,"props":309,"children":310},{},[311,316],{"type":25,"tag":195,"props":312,"children":314},{"className":313},[],[315],{"type":30,"value":302},{"type":30,"value":317}," is the largest and most specific file. It is the only file that changes if an API endpoint changes.",{"type":25,"tag":49,"props":319,"children":320},{},[],{"type":25,"tag":53,"props":322,"children":324},{"id":323},"step-three-the-first-draft-had-nine-duplicates",[325],{"type":30,"value":326},"Step three: the first draft had nine duplicates",{"type":25,"tag":26,"props":328,"children":329},{},[330],{"type":30,"value":331},"Here is what the first draft actually looked like: nine areas of duplicated content. Five were exact copies of the same information in two files. Four were partial overlaps where the same rule appeared at different levels of detail.",{"type":25,"tag":26,"props":333,"children":334},{},[335],{"type":30,"value":336},"This was not caught until reading all seven files side by side — something that sounds obvious but is easy to skip when you are writing file by file. The duplicates were invisible until you looked at the whole picture at once.",{"type":25,"tag":26,"props":338,"children":339},{},[340],{"type":30,"value":341},"The most glaring example was the LinkedIn rate limit. It appeared in four places:",{"type":25,"tag":343,"props":344,"children":345},"ul",{},[346,359,370,381],{"type":25,"tag":347,"props":348,"children":349},"li",{},[350,352,357],{"type":30,"value":351},"In ",{"type":25,"tag":195,"props":353,"children":355},{"className":354},[],[356],{"type":30,"value":268},{"type":30,"value":358}," as a rule: \"20 invitations\u002Fday\u002Faccount\"",{"type":25,"tag":347,"props":360,"children":361},{},[362,363,368],{"type":30,"value":351},{"type":25,"tag":195,"props":364,"children":366},{"className":365},[],[367],{"type":30,"value":200},{"type":30,"value":369}," as a principle: \"protect the commercial's LinkedIn account\"",{"type":25,"tag":347,"props":371,"children":372},{},[373,374,379],{"type":30,"value":351},{"type":25,"tag":195,"props":375,"children":377},{"className":376},[],[378],{"type":30,"value":302},{"type":30,"value":380}," as implementation: \"queue if exceeded, abort if account restricted\"",{"type":25,"tag":347,"props":382,"children":383},{},[384,385,390],{"type":30,"value":351},{"type":25,"tag":195,"props":386,"children":388},{"className":387},[],[389],{"type":30,"value":285},{"type":30,"value":391}," as a monitoring task: \"alert at 75%, stop at 100%\"",{"type":25,"tag":26,"props":393,"children":394},{},[395,397,403],{"type":30,"value":396},"At first glance this looks reasonable — each file adds a different perspective. But the number ",{"type":25,"tag":195,"props":398,"children":400},{"className":399},[],[401],{"type":30,"value":402},"20",{"type":30,"value":404}," appeared verbatim in three of those files. If that limit changes, you need to remember to update three separate files. That is how agents start behaving in contradictory ways in production.",{"type":25,"tag":26,"props":406,"children":407},{},[408],{"type":30,"value":409},"The fix was to give each file a single voice and a single ownership:",{"type":25,"tag":343,"props":411,"children":412},{},[413,430,445,460],{"type":25,"tag":347,"props":414,"children":415},{},[416,421,423,428],{"type":25,"tag":417,"props":418,"children":419},"strong",{},[420],{"type":30,"value":268},{"type":30,"value":422}," owns ",{"type":25,"tag":103,"props":424,"children":425},{},[426],{"type":30,"value":427},"what",{"type":30,"value":429}," the rule is (the number: 20 invitations\u002Fday)",{"type":25,"tag":347,"props":431,"children":432},{},[433,437,438,443],{"type":25,"tag":417,"props":434,"children":435},{},[436],{"type":30,"value":302},{"type":30,"value":422},{"type":25,"tag":103,"props":439,"children":440},{},[441],{"type":30,"value":442},"how",{"type":30,"value":444}," it is implemented (queue, abort, notify)",{"type":25,"tag":347,"props":446,"children":447},{},[448,452,453,458],{"type":25,"tag":417,"props":449,"children":450},{},[451],{"type":30,"value":200},{"type":30,"value":422},{"type":25,"tag":103,"props":454,"children":455},{},[456],{"type":30,"value":457},"why",{"type":30,"value":459}," it matters (the principle, not the number)",{"type":25,"tag":347,"props":461,"children":462},{},[463,467,468,473],{"type":25,"tag":417,"props":464,"children":465},{},[466],{"type":30,"value":285},{"type":30,"value":422},{"type":25,"tag":103,"props":469,"children":470},{},[471],{"type":30,"value":472},"when",{"type":30,"value":474}," to act on it (75% and 100% thresholds)",{"type":25,"tag":26,"props":476,"children":477},{},[478,480,485],{"type":30,"value":479},"After deduplication, the number ",{"type":25,"tag":195,"props":481,"children":483},{"className":482},[],[484],{"type":30,"value":402},{"type":30,"value":486}," appears in exactly one file. The others reference the concept without repeating the value.",{"type":25,"tag":26,"props":488,"children":489},{},[490,492,497,499,504,506,511,513,518],{"type":30,"value":491},"The database schema had the same problem. It appeared partially in ",{"type":25,"tag":195,"props":493,"children":495},{"className":494},[],[496],{"type":30,"value":268},{"type":30,"value":498},", partially in ",{"type":25,"tag":195,"props":500,"children":502},{"className":501},[],[503],{"type":30,"value":302},{"type":30,"value":505},", and was referenced in ",{"type":25,"tag":195,"props":507,"children":509},{"className":508},[],[510],{"type":30,"value":234},{"type":30,"value":512},". After the audit, the complete schema lives only in ",{"type":25,"tag":195,"props":514,"children":516},{"className":515},[],[517],{"type":30,"value":302},{"type":30,"value":519},". Every other file that needs to reference a table names it without reproducing its structure.",{"type":25,"tag":26,"props":521,"children":522},{},[523],{"type":30,"value":524},"Duplicates are not just redundant. They are the symptom of unclear ownership. Every duplicate found during this process was evidence of a decision that had not been made yet about which file owns that piece of information.",{"type":25,"tag":49,"props":526,"children":527},{},[],{"type":25,"tag":53,"props":529,"children":531},{"id":530},"step-four-the-pipeline-as-agentsmd",[532],{"type":30,"value":533},"Step four: the pipeline as AGENTS.md",{"type":25,"tag":26,"props":535,"children":536},{},[537,539,544],{"type":30,"value":538},"The most important single file is ",{"type":25,"tag":195,"props":540,"children":542},{"className":541},[],[543],{"type":30,"value":234},{"type":30,"value":545},". It is where the six-phase pipeline becomes something the model can actually execute — not prose describing the process, but structured pseudocode with explicit loop conditions, decision branches, and escalation points.",{"type":25,"tag":26,"props":547,"children":548},{},[549],{"type":25,"tag":117,"props":550,"children":553},{"alt":551,"src":552},"Sabrina's six-phase pipeline","\u002Fimages\u002Fdiagrams\u002Fdiagram-02-pipeline.jpg",[],{"type":25,"tag":26,"props":555,"children":556},{},[557,559,564],{"type":30,"value":558},"The key insight in ",{"type":25,"tag":195,"props":560,"children":562},{"className":561},[],[563],{"type":30,"value":234},{"type":30,"value":565}," is the loop condition. The agent does not just run the pipeline once — it loops through companies, processing one lead per company, until it reaches the requested number. The Job Coordinator tracks five counters: created, incomplete, discarded, connections sent, and the target N. The loop is deterministic and stops cleanly.",{"type":25,"tag":26,"props":567,"children":568},{},[569],{"type":30,"value":570},"The loop check is a single line:",{"type":25,"tag":572,"props":573,"children":575},"pre",{"code":574},"n_created == n_requested?\n  NO  → loop to next company (Phase 2)\n  YES → Discord summary\n",[576],{"type":25,"tag":195,"props":577,"children":578},{"__ignoreMap":8},[579],{"type":30,"value":574},{"type":25,"tag":26,"props":581,"children":582},{},[583],{"type":30,"value":584},"Simple. But without it written explicitly, the model has to infer the stopping condition from prose — and prose is ambiguous.",{"type":25,"tag":49,"props":586,"children":587},{},[],{"type":25,"tag":53,"props":589,"children":591},{"id":590},"step-five-the-decision-rules-table",[592],{"type":30,"value":593},"Step five: the decision rules table",{"type":25,"tag":26,"props":595,"children":596},{},[597],{"type":30,"value":598},"The specification had many implied decisions buried in prose. Situations where the pipeline did not give a clear answer.",{"type":25,"tag":343,"props":600,"children":601},{},[602,607,612],{"type":25,"tag":347,"props":603,"children":604},{},[605],{"type":30,"value":606},"What do you do if Lusha returns a generic email?",{"type":25,"tag":347,"props":608,"children":609},{},[610],{"type":30,"value":611},"What if a company is already in Odoo as a lead but not an active client?",{"type":25,"tag":347,"props":613,"children":614},{},[615],{"type":30,"value":616},"What if the LinkedIn rate limit is hit halfway through a Job?",{"type":25,"tag":26,"props":618,"children":619},{},[620,622,627],{"type":30,"value":621},"These were extracted into a single decision table in ",{"type":25,"tag":195,"props":623,"children":625},{"className":624},[],[626],{"type":30,"value":234},{"type":30,"value":628},". Not because the table is more readable — it is not — but because an explicit table is something the model can actually apply. Prose requires interpretation. A table requires lookup.",{"type":25,"tag":161,"props":630,"children":631},{},[632,648],{"type":25,"tag":165,"props":633,"children":634},{},[635],{"type":25,"tag":169,"props":636,"children":637},{},[638,643],{"type":25,"tag":173,"props":639,"children":640},{},[641],{"type":30,"value":642},"If",{"type":25,"tag":173,"props":644,"children":645},{},[646],{"type":30,"value":647},"Then",{"type":25,"tag":184,"props":649,"children":650},{},[651,664,677,690,703,716,729],{"type":25,"tag":169,"props":652,"children":653},{},[654,659],{"type":25,"tag":191,"props":655,"children":656},{},[657],{"type":30,"value":658},"Generic email returned (info@, contact@…)",{"type":25,"tag":191,"props":660,"children":661},{},[662],{"type":30,"value":663},"Treat as not found. Retry by name + company. If still generic → Incomplete Contact.",{"type":25,"tag":169,"props":665,"children":666},{},[667,672],{"type":25,"tag":191,"props":668,"children":669},{},[670],{"type":30,"value":671},"Company in Odoo as lead (not active client)",{"type":25,"tag":191,"props":673,"children":674},{},[675],{"type":30,"value":676},"Do not exclude the company. Check if the specific person already exists.",{"type":25,"tag":169,"props":678,"children":679},{},[680,685],{"type":25,"tag":191,"props":681,"children":682},{},[683],{"type":30,"value":684},"Prior LinkedIn invitation to same user ID",{"type":25,"tag":191,"props":686,"children":687},{},[688],{"type":30,"value":689},"Skip. Log \"duplicate avoided\". Do not count as sent. Continue.",{"type":25,"tag":169,"props":691,"children":692},{},[693,698],{"type":25,"tag":191,"props":694,"children":695},{},[696],{"type":30,"value":697},"Rate limit 100% (20\u002F20)",{"type":25,"tag":191,"props":699,"children":700},{},[701],{"type":30,"value":702},"Stop invitations. Notify. Queue for next day. Leads stay in Odoo.",{"type":25,"tag":169,"props":704,"children":705},{},[706,711],{"type":25,"tag":191,"props":707,"children":708},{},[709],{"type":30,"value":710},"Fewer than N companies found after ×4 search",{"type":25,"tag":191,"props":712,"children":713},{},[714],{"type":30,"value":715},"Create what was found. State the gap. Suggest broadening ICP in summary.",{"type":25,"tag":169,"props":717,"children":718},{},[719,724],{"type":25,"tag":191,"props":720,"children":721},{},[722],{"type":30,"value":723},"Conflicting instructions",{"type":25,"tag":191,"props":725,"children":726},{},[727],{"type":30,"value":728},"SOUL.md limits → AGENTS.md rules → user request.",{"type":25,"tag":169,"props":730,"children":731},{},[732,737],{"type":25,"tag":191,"props":733,"children":734},{},[735],{"type":30,"value":736},"Unknown situation",{"type":25,"tag":191,"props":738,"children":739},{},[740],{"type":30,"value":741},"Acknowledge. Do not guess. Notify commercial and wait.",{"type":25,"tag":26,"props":743,"children":744},{},[745],{"type":30,"value":746},"The \"company already in Odoo as a lead\" case is a good example of a decision that was not obvious. The naive implementation would exclude any company already in the system. The right implementation is more nuanced: exclude active clients (they are already customers), but a company that is just a lead from a previous Job should not block a new search for a different person at that company. That distinction took a full iteration to land on.",{"type":25,"tag":49,"props":748,"children":749},{},[],{"type":25,"tag":53,"props":751,"children":753},{"id":752},"step-six-soulmd-had-to-be-written-from-scratch",[754],{"type":30,"value":755},"Step six: SOUL.md had to be written from scratch",{"type":25,"tag":26,"props":757,"children":758},{},[759,761,766],{"type":30,"value":760},"This was the hardest part. After mapping all the spec content to files, ",{"type":25,"tag":195,"props":762,"children":764},{"className":763},[],[765],{"type":30,"value":200},{"type":30,"value":767}," was essentially empty. The specification covered everything the agent does but said almost nothing about who the agent is.",{"type":25,"tag":26,"props":769,"children":770},{},[771,773,778,780,785],{"type":30,"value":772},"The first attempt at ",{"type":25,"tag":195,"props":774,"children":776},{"className":775},[],[777],{"type":30,"value":200},{"type":30,"value":779}," was a list of rules that belonged in ",{"type":25,"tag":195,"props":781,"children":783},{"className":782},[],[784],{"type":30,"value":234},{"type":30,"value":786},". It was scrapped entirely and rewritten from a different starting point: not \"what does the spec say?\" but \"what would this agent do when the spec runs out?\"",{"type":25,"tag":26,"props":788,"children":789},{},[790,792,797,799,804],{"type":30,"value":791},"That is the right question for ",{"type":25,"tag":195,"props":793,"children":795},{"className":794},[],[796],{"type":30,"value":200},{"type":30,"value":798},". Not rules — principles. Rules live in ",{"type":25,"tag":195,"props":800,"children":802},{"className":801},[],[803],{"type":30,"value":234},{"type":30,"value":805},". Principles are what the agent reaches for when there is no rule that covers the situation.",{"type":25,"tag":26,"props":807,"children":808},{},[809],{"type":30,"value":810},"For Sabrina, five emerged by going through every ambiguous scenario in the spec and asking what value judgement the agent would need to make:",{"type":25,"tag":26,"props":812,"children":813},{},[814,819],{"type":25,"tag":417,"props":815,"children":816},{},[817],{"type":30,"value":818},"1. Quality over volume.",{"type":30,"value":820}," Never relax a validation rule to reach the requested number of leads. Four complete leads beat ten incomplete ones.",{"type":25,"tag":26,"props":822,"children":823},{},[824,829],{"type":25,"tag":417,"props":825,"children":826},{},[827],{"type":30,"value":828},"2. Full traceability.",{"type":30,"value":830}," Every lead in Odoo must be traceable to its Job, its commercial, and the completeness of its data. If it cannot be traced, it does not ship.",{"type":25,"tag":26,"props":832,"children":833},{},[834,839],{"type":25,"tag":417,"props":835,"children":836},{},[837],{"type":30,"value":838},"3. Protect the LinkedIn accounts.",{"type":30,"value":840}," The rate limit is not a guideline. It is a ceiling that protects the commercial's personal LinkedIn account from restriction.",{"type":25,"tag":26,"props":842,"children":843},{},[844,849],{"type":25,"tag":417,"props":845,"children":846},{},[847],{"type":30,"value":848},"4. Validate, do not assume.",{"type":30,"value":850}," Missing ICP field? Ask. Unknown commercial? Abort. The cost of starting wrong is always higher than the cost of asking first.",{"type":25,"tag":26,"props":852,"children":853},{},[854,859],{"type":25,"tag":417,"props":855,"children":856},{},[857],{"type":30,"value":858},"5. Never block a Job on a single lead.",{"type":30,"value":860}," If Lusha fails, mark and move on. If an API errors, retry twice and move on. The Job continues unless the infrastructure is completely down.",{"type":25,"tag":26,"props":862,"children":863},{},[864],{"type":30,"value":865},"None of these appear in the original specification. They are derived from reading what the spec implicitly assumes the agent will do when things go wrong.",{"type":25,"tag":49,"props":867,"children":868},{},[],{"type":25,"tag":53,"props":870,"children":872},{"id":871},"step-seven-lusha-enrichment-the-decision-tree-that-matters-most",[873],{"type":30,"value":874},"Step seven: Lusha enrichment — the decision tree that matters most",{"type":25,"tag":26,"props":876,"children":877},{},[878],{"type":30,"value":879},"The Lusha enrichment logic is the most consequential decision in the pipeline. If it fails, the lead still gets created — but without contact data it is significantly less useful.",{"type":25,"tag":26,"props":881,"children":882},{},[883],{"type":25,"tag":117,"props":884,"children":887},{"alt":885,"src":886},"Lusha enrichment decision tree","\u002Fimages\u002Fdiagrams\u002Fdiagram-04-lusha.jpg",[],{"type":25,"tag":26,"props":889,"children":890},{},[891],{"type":30,"value":892},"The critical design decision: always create the lead, even if both enrichment attempts fail. Never block the Job. Mark the lead, log the reason, and let the commercial decide what to do with it. This sounds obvious written down, but the first version of the spec implied stopping the Job if enrichment failed completely — which would mean losing all the work done to find and validate that lead.",{"type":25,"tag":49,"props":894,"children":895},{},[],{"type":25,"tag":53,"props":897,"children":899},{"id":898},"step-eight-heartbeatmd-the-agent-that-runs-without-being-asked",[900],{"type":30,"value":901},"Step eight: HEARTBEAT.md — the agent that runs without being asked",{"type":25,"tag":26,"props":903,"children":904},{},[905],{"type":30,"value":906},"The heartbeat was the most interesting file to design. The specification describes Sabrina as an on-demand agent — the commercial asks, Sabrina delivers. But a real production agent needs to do things without being asked: monitor API health, enforce rate limits, detect stalled Jobs, validate credentials on startup.",{"type":25,"tag":26,"props":908,"children":909},{},[910],{"type":25,"tag":117,"props":911,"children":914},{"alt":912,"src":913},"Sabrina's three heartbeat frequencies","\u002Fimages\u002Fdiagrams\u002Fdiagram-03-heartbeat.jpg",[],{"type":25,"tag":26,"props":916,"children":917},{},[918,920,925],{"type":30,"value":919},"The most important rule in ",{"type":25,"tag":195,"props":921,"children":923},{"className":922},[],[924],{"type":30,"value":285},{"type":30,"value":926}," is the autonomy limit: the heartbeat never takes destructive or irreversible actions without explicit confirmation. It monitors, alerts, and queues. It does not delete, does not send, does not modify. If it detects a problem, it notifies and waits.",{"type":25,"tag":26,"props":928,"children":929},{},[930],{"type":30,"value":931},"The startup validation is equally important: before accepting any Job, Sabrina validates all four credentials (Discord, Unipile, Lusha, Odoo). A failed credential means no Jobs — not a degraded mode, not a retry loop, not a silent failure.",{"type":25,"tag":49,"props":933,"children":934},{},[],{"type":25,"tag":53,"props":936,"children":938},{"id":937},"step-nine-where-does-the-database-schema-live",[939],{"type":30,"value":940},"Step nine: where does the database schema live?",{"type":25,"tag":26,"props":942,"children":943},{},[944],{"type":30,"value":945},"One decision cost more iterations than any other: where does the agent's internal database schema belong?",{"type":25,"tag":26,"props":947,"children":948},{},[949,951,956,958,963,965,970,972,977],{"type":30,"value":950},"The schema defines five tables: commercials mapping, ICP templates, jobs, processed leads, and LinkedIn invitations. It is referenced by almost every tool in ",{"type":25,"tag":195,"props":952,"children":954},{"className":953},[],[955],{"type":30,"value":302},{"type":30,"value":957}," and by the session loop in ",{"type":25,"tag":195,"props":959,"children":961},{"className":960},[],[962],{"type":30,"value":234},{"type":30,"value":964},". The first instinct was to put it in ",{"type":25,"tag":195,"props":966,"children":968},{"className":967},[],[969],{"type":30,"value":268},{"type":30,"value":971}," — it felt like \"something the agent needs to know\". But ",{"type":25,"tag":195,"props":973,"children":975},{"className":974},[],[976],{"type":30,"value":268},{"type":30,"value":978}," is for evergreen facts that change rarely, not for technical specifications.",{"type":25,"tag":26,"props":980,"children":981},{},[982,984,989,991,996],{"type":30,"value":983},"The second attempt was to split it: put the table names in ",{"type":25,"tag":195,"props":985,"children":987},{"className":986},[],[988],{"type":30,"value":268},{"type":30,"value":990}," and the full column definitions in ",{"type":25,"tag":195,"props":992,"children":994},{"className":993},[],[995],{"type":30,"value":302},{"type":30,"value":997},". That created the exact duplication problem described earlier.",{"type":25,"tag":26,"props":999,"children":1000},{},[1001,1003,1008,1010,1015,1017,1022],{"type":30,"value":1002},"The right answer — which took three iterations to land on — is that the complete schema belongs entirely in ",{"type":25,"tag":195,"props":1004,"children":1006},{"className":1005},[],[1007],{"type":30,"value":302},{"type":30,"value":1009},", because it is the file that describes what the agent can reach for and how. ",{"type":25,"tag":195,"props":1011,"children":1013},{"className":1012},[],[1014],{"type":30,"value":268},{"type":30,"value":1016}," references the table names where needed, without reproducing any column definitions. ",{"type":25,"tag":195,"props":1018,"children":1020},{"className":1019},[],[1021],{"type":30,"value":234},{"type":30,"value":1023}," references the table names in the pipeline logic, also without reproducing structure.",{"type":25,"tag":26,"props":1025,"children":1026},{},[1027],{"type":30,"value":1028},"The rule that emerged from this: if a piece of information changes together with something else, it belongs in the same file as that something else. The schema changes when the tools change. So the schema lives with the tools.",{"type":25,"tag":49,"props":1030,"children":1031},{},[],{"type":25,"tag":53,"props":1033,"children":1035},{"id":1034},"what-we-learned",[1036],{"type":30,"value":1037},"What we learned",{"type":25,"tag":26,"props":1039,"children":1040},{},[1041,1046],{"type":25,"tag":417,"props":1042,"children":1043},{},[1044],{"type":30,"value":1045},"The filing problem is the design problem.",{"type":30,"value":1047}," Where you put a piece of information is a decision about who owns it, when it changes, and what happens when it conflicts with something else. Getting the filing right forces you to think clearly about the agent's responsibilities — and you cannot do that by writing file by file without stepping back.",{"type":25,"tag":26,"props":1049,"children":1050},{},[1051,1056],{"type":25,"tag":417,"props":1052,"children":1053},{},[1054],{"type":30,"value":1055},"Read all seven files together before calling the first draft done.",{"type":30,"value":1057}," The duplicates were invisible until the files were read as a set. Writing file by file creates blind spots. The audit pass — reading all seven looking specifically for the same information in multiple places — is not optional.",{"type":25,"tag":26,"props":1059,"children":1060},{},[1061,1071],{"type":25,"tag":417,"props":1062,"children":1063},{},[1064,1069],{"type":25,"tag":195,"props":1065,"children":1067},{"className":1066},[],[1068],{"type":30,"value":200},{"type":30,"value":1070}," cannot be written from the spec.",{"type":30,"value":1072}," It has to be written from the gaps in the spec. The question is not \"what does the spec say?\" but \"what would this agent do when the spec runs out?\" That is a different kind of reading, and it requires a separate pass.",{"type":25,"tag":26,"props":1074,"children":1075},{},[1076,1081],{"type":25,"tag":417,"props":1077,"children":1078},{},[1079],{"type":30,"value":1080},"The hardest decisions are not technical.",{"type":30,"value":1082}," The database schema question, the Lusha fallback behaviour, the deduplication rules for companies — none of these required complex logic. They required making a choice and owning it. The spec leaves many of these choices implicit. Making them explicit is the actual work.",{"type":25,"tag":26,"props":1084,"children":1085},{},[1086,1091,1093,1098],{"type":25,"tag":417,"props":1087,"children":1088},{},[1089],{"type":30,"value":1090},"The heartbeat earns its file.",{"type":30,"value":1092}," It is tempting to skip ",{"type":25,"tag":195,"props":1094,"children":1096},{"className":1095},[],[1097],{"type":30,"value":285},{"type":30,"value":1099}," for simple agents. But any agent that touches rate-limited external APIs, writes to a production CRM, and runs unattended needs autonomous health monitoring. The heartbeat is what separates a demo from a production deployment.",{"type":25,"tag":70,"props":1101,"children":1102},{},[1103],{"type":25,"tag":26,"props":1104,"children":1105},{},[1106],{"type":30,"value":1107},"The seven-file spec works because it forces you to have these conversations before the code is written. The files are not documentation of what was built — they are the specification of how the agent thinks.",{"type":25,"tag":49,"props":1109,"children":1110},{},[],{"type":25,"tag":53,"props":1112,"children":1114},{"id":1113},"what-comes-next",[1115],{"type":30,"value":1116},"What comes next",{"type":25,"tag":26,"props":1118,"children":1119},{},[1120],{"type":30,"value":1121},"These files are now going into real use. When the team starts running live prospecting Jobs, Sabrina will process real leads with real LinkedIn accounts — that is when the spec meets reality. The follow-up will be a before\u002Fafter of the seven files: what changed after the first production runs, which rules needed updating, and which decisions turned out to be wrong — grounded in a commercial team at work, not a hypothetical walkthrough. That post will ship once there is enough real data to make it worth reading.",{"type":25,"tag":49,"props":1123,"children":1124},{},[],{"type":25,"tag":26,"props":1126,"children":1127},{},[1128],{"type":25,"tag":103,"props":1129,"children":1130},{},[1131,1133,1140],{"type":30,"value":1132},"The seven-file framework is documented and free to fork at ",{"type":25,"tag":38,"props":1134,"children":1137},{"href":1135,"rel":1136},"https:\u002F\u002Fbuild-your-agents.vercel.app",[42],[1138],{"type":30,"value":1139},"build-your-agents.vercel.app",{"type":30,"value":1141},". The spec, templates, and session loop reference are all public.",{"title":8,"searchDepth":1143,"depth":1143,"links":1144},2,[1145,1146,1147,1148,1149,1150,1151,1152,1153,1154,1155,1156],{"id":55,"depth":1143,"text":58},{"id":88,"depth":1143,"text":91},{"id":132,"depth":1143,"text":135},{"id":323,"depth":1143,"text":326},{"id":530,"depth":1143,"text":533},{"id":590,"depth":1143,"text":593},{"id":752,"depth":1143,"text":755},{"id":871,"depth":1143,"text":874},{"id":898,"depth":1143,"text":901},{"id":937,"depth":1143,"text":940},{"id":1034,"depth":1143,"text":1037},{"id":1113,"depth":1143,"text":1116},"markdown","content:posts:001-Sabrina.md","content","posts\u002F001-Sabrina.md","posts\u002F001-Sabrina","md",{"_path":1164,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":1165,"description":1166,"date":1167,"tags":1168,"cover":1172,"draft":7,"author":19,"authorIntro":1173,"body":1174,"_type":1157,"_id":1899,"_source":1159,"_file":1900,"_stem":1901,"_extension":1162},"\u002Fposts\u002Fwelcome","Welcome: living documentation, agents, and this site","Opening post: why this project exists, what we actually built for anyone who lands here, and how it connects OpenClaw, Resizes, and personal experiments.","2026-05-12",[1169,13,16,1170,1171],"documentation","nuxt","architecture","\u002Fimages\u002Fposts\u002FopenclawBYA.png","I build and refine AI agents with OpenClaw—professionally at Resizes, and on personal projects where I can take more risk. This site is where I publish what I learn as I go: partly to clarify my own thinking, partly in case these notes help someone facing a similar problem—or invite feedback that saves us all a few wrong turns.",{"type":22,"children":1175,"toc":1887},[1176,1222,1241,1247,1318,1330,1437,1456,1490,1509,1515,1547,1580,1586,1598,1605,1652,1664,1670,1699,1753,1759,1785,1811,1817,1850,1854,1864,1867,1879],{"type":25,"tag":26,"props":1177,"children":1178},{},[1179,1181,1186,1188,1193,1195,1200,1202,1207,1209,1214,1216,1221],{"type":30,"value":1180},"This blog is ",{"type":25,"tag":417,"props":1182,"children":1183},{},[1184],{"type":30,"value":1185},"living, personal documentation",{"type":30,"value":1187},". It is not a closed manual or a finished methodology. I am using it to record ",{"type":25,"tag":417,"props":1189,"children":1190},{},[1191],{"type":30,"value":1192},"how my understanding evolves",{"type":30,"value":1194}," as I ",{"type":25,"tag":417,"props":1196,"children":1197},{},[1198],{"type":30,"value":1199},"design, ship, and improve agents",{"type":30,"value":1201},"—including with ",{"type":25,"tag":417,"props":1203,"children":1204},{},[1205],{"type":30,"value":1206},"OpenClaw",{"type":30,"value":1208},"—in both ",{"type":25,"tag":417,"props":1210,"children":1211},{},[1212],{"type":30,"value":1213},"professional work at Resizes",{"type":30,"value":1215}," and ",{"type":25,"tag":417,"props":1217,"children":1218},{},[1219],{"type":30,"value":1220},"independent exploration",{"type":30,"value":154},{"type":25,"tag":26,"props":1223,"children":1224},{},[1225,1227,1232,1234,1239],{"type":30,"value":1226},"If I capture decisions while they are still fresh, I do more than tidy my own mental model. I leave a trace that may help ",{"type":25,"tag":417,"props":1228,"children":1229},{},[1230],{"type":30,"value":1231},"someone who hits the same wall later",{"type":30,"value":1233},", or attract ",{"type":25,"tag":417,"props":1235,"children":1236},{},[1237],{"type":30,"value":1238},"a correction, a link, or a conversation",{"type":30,"value":1240}," that would otherwise take weeks of trial and error to reach. The blog is where that narrative can breathe—more patiently than in a cramped README or a fleeting social thread.",{"type":25,"tag":53,"props":1242,"children":1244},{"id":1243},"what-this-project-is",[1245],{"type":30,"value":1246},"What this project is",{"type":25,"tag":26,"props":1248,"children":1249},{},[1250,1252,1257,1259,1264,1266,1271,1273,1278,1280,1285,1286,1291,1292,1297,1298,1303,1304,1309,1311,1316],{"type":30,"value":1251},"On the surface, ",{"type":25,"tag":417,"props":1253,"children":1254},{},[1255],{"type":30,"value":1256},"build\u002Fyour\u002Fagents",{"type":30,"value":1258}," is a ",{"type":25,"tag":417,"props":1260,"children":1261},{},[1262],{"type":30,"value":1263},"Nuxt 3",{"type":30,"value":1265}," site that presents a ",{"type":25,"tag":417,"props":1267,"children":1268},{},[1269],{"type":30,"value":1270},"seven-file architecture",{"type":30,"value":1272}," for modular, personal AI agents. The files are intentional labels: ",{"type":25,"tag":417,"props":1274,"children":1275},{},[1276],{"type":30,"value":1277},"Soul",{"type":30,"value":1279},", ",{"type":25,"tag":417,"props":1281,"children":1282},{},[1283],{"type":30,"value":1284},"Identity",{"type":30,"value":1279},{"type":25,"tag":417,"props":1287,"children":1288},{},[1289],{"type":30,"value":1290},"Agents",{"type":30,"value":1279},{"type":25,"tag":417,"props":1293,"children":1294},{},[1295],{"type":30,"value":1296},"User",{"type":30,"value":1279},{"type":25,"tag":417,"props":1299,"children":1300},{},[1301],{"type":30,"value":1302},"Memory",{"type":30,"value":1279},{"type":25,"tag":417,"props":1305,"children":1306},{},[1307],{"type":30,"value":1308},"Heartbeat",{"type":30,"value":1310},", and ",{"type":25,"tag":417,"props":1312,"children":1313},{},[1314],{"type":30,"value":1315},"Tools",{"type":30,"value":1317},". Each plays a clear role—from tone and boundaries to memory, cadence, and permitted tooling.",{"type":25,"tag":26,"props":1319,"children":1320},{},[1321,1323,1328],{"type":30,"value":1322},"The templates are ",{"type":25,"tag":417,"props":1324,"children":1325},{},[1326],{"type":30,"value":1327},"not empty placeholders",{"type":30,"value":1329},". At a glance:",{"type":25,"tag":343,"props":1331,"children":1332},{},[1333,1349,1358,1381,1390,1399,1422],{"type":25,"tag":347,"props":1334,"children":1335},{},[1336,1340,1342,1347],{"type":25,"tag":417,"props":1337,"children":1338},{},[1339],{"type":30,"value":1277},{"type":30,"value":1341}," — who the agent is: voice, values, capabilities, and ",{"type":25,"tag":417,"props":1343,"children":1344},{},[1345],{"type":30,"value":1346},"hard limits",{"type":30,"value":1348}," (what must never happen).",{"type":25,"tag":347,"props":1350,"children":1351},{},[1352,1356],{"type":25,"tag":417,"props":1353,"children":1354},{},[1355],{"type":30,"value":1284},{"type":30,"value":1357}," — where it lives: metadata, routing, model configuration, multi-agent and session settings.",{"type":25,"tag":347,"props":1359,"children":1360},{},[1361,1365,1367,1372,1374,1379],{"type":25,"tag":417,"props":1362,"children":1363},{},[1364],{"type":30,"value":1290},{"type":30,"value":1366}," — how it operates: workflows, ",{"type":25,"tag":417,"props":1368,"children":1369},{},[1370],{"type":30,"value":1371},"decision rules",{"type":30,"value":1373},", memory rules, escalation, and communication patterns—the file that ",{"type":25,"tag":103,"props":1375,"children":1376},{},[1377],{"type":30,"value":1378},"reads",{"type":30,"value":1380}," the others in a defined order.",{"type":25,"tag":347,"props":1382,"children":1383},{},[1384,1388],{"type":25,"tag":417,"props":1385,"children":1386},{},[1387],{"type":30,"value":1296},{"type":30,"value":1389}," — who it serves: your preferences, projects, contacts, priorities, and explicit “do not do” lines.",{"type":25,"tag":347,"props":1391,"children":1392},{},[1393,1397],{"type":25,"tag":417,"props":1394,"children":1395},{},[1396],{"type":30,"value":1315},{"type":30,"value":1398}," — what it may invoke: skills, MCPs, built-ins, selection order, and error handling (the “static map” of capability).",{"type":25,"tag":347,"props":1400,"children":1401},{},[1402,1406,1408,1413,1415,1420],{"type":25,"tag":417,"props":1403,"children":1404},{},[1405],{"type":30,"value":1302},{"type":30,"value":1407}," — what persists as ",{"type":25,"tag":417,"props":1409,"children":1410},{},[1411],{"type":30,"value":1412},"evergreen knowledge",{"type":30,"value":1414},": confirmed facts, usually one line per fact, ",{"type":25,"tag":417,"props":1416,"children":1417},{},[1418],{"type":30,"value":1419},"superseded",{"type":30,"value":1421}," rather than silently deleted when something changes.",{"type":25,"tag":347,"props":1423,"children":1424},{},[1425,1429,1431,1436],{"type":25,"tag":417,"props":1426,"children":1427},{},[1428],{"type":30,"value":1308},{"type":30,"value":1430}," — how it acts on its own time: scheduled tasks, reviews, alerts, and rules for ",{"type":25,"tag":417,"props":1432,"children":1433},{},[1434],{"type":30,"value":1435},"what must never run without your confirmation",{"type":30,"value":154},{"type":25,"tag":26,"props":1438,"children":1439},{},[1440,1442,1447,1449,1455],{"type":30,"value":1441},"On the site, those files are also grouped into ",{"type":25,"tag":417,"props":1443,"children":1444},{},[1445],{"type":30,"value":1446},"four tiers",{"type":30,"value":1448}," (core identity, orchestration, operational inputs, state and memory). That layer answers “what do I trust first?” and “what sits on top of what” before you open a single ",{"type":25,"tag":195,"props":1450,"children":1452},{"className":1451},[],[1453],{"type":30,"value":1454},".md",{"type":30,"value":154},{"type":25,"tag":26,"props":1457,"children":1458},{},[1459,1461,1466,1468,1474,1476,1481,1483,1488],{"type":30,"value":1460},"The site does not stop at the landing page. A ",{"type":25,"tag":417,"props":1462,"children":1463},{},[1464],{"type":30,"value":1465},"Documentation",{"type":30,"value":1467}," section (",{"type":25,"tag":195,"props":1469,"children":1471},{"className":1470},[],[1472],{"type":30,"value":1473},"\u002Fdocs",{"type":30,"value":1475},") is the working centre for anyone who wants to ",{"type":25,"tag":417,"props":1477,"children":1478},{},[1479],{"type":30,"value":1480},"read, copy, or adapt",{"type":30,"value":1482}," the seven files: each layer is laid out with context, preview toggles, and links to the raw Markdown you can drop into your own agent setup. The ",{"type":25,"tag":417,"props":1484,"children":1485},{},[1486],{"type":30,"value":1487},"blog",{"type":30,"value":1489}," (where you are now) is for longer essays, field notes, and the occasional personal aside—so the “spec” stays crisp while the story can stretch.",{"type":25,"tag":26,"props":1491,"children":1492},{},[1493,1495,1500,1502,1507],{"type":30,"value":1494},"Visually, the project commits to a ",{"type":25,"tag":417,"props":1496,"children":1497},{},[1498],{"type":30,"value":1499},"bold, brutalist palette",{"type":30,"value":1501},": strong type (Archivo Black, Fraunces, Space Mono), heavy borders, hard shadows, and saturated colour that avoids generic “startup neutral.” That is not ornamentation alone. Documentation you live in for hours should feel ",{"type":25,"tag":417,"props":1503,"children":1504},{},[1505],{"type":30,"value":1506},"authored",{"type":30,"value":1508},"—so visitors sense a human behind the decisions, not only a theme.",{"type":25,"tag":53,"props":1510,"children":1512},{"id":1511},"how-this-fits-openclaw-resizes-and-personal-use",[1513],{"type":30,"value":1514},"How this fits OpenClaw, Resizes, and personal use",{"type":25,"tag":26,"props":1516,"children":1517},{},[1518,1520,1525,1527,1531,1533,1538,1540,1545],{"type":30,"value":1519},"The ecosystem around ",{"type":25,"tag":417,"props":1521,"children":1522},{},[1523],{"type":30,"value":1524},"capable agents",{"type":30,"value":1526},"—tool use, memory, reasoning loops—is moving quickly. At ",{"type":25,"tag":417,"props":1528,"children":1529},{},[1530],{"type":30,"value":45},{"type":30,"value":1532},", refinements to rules, context windows, and guardrails directly affect ",{"type":25,"tag":417,"props":1534,"children":1535},{},[1536],{"type":30,"value":1537},"quality, cost, and trust",{"type":30,"value":1539},". In ",{"type":25,"tag":417,"props":1541,"children":1542},{},[1543],{"type":30,"value":1544},"personal",{"type":30,"value":1546}," projects, the same questions return—but with more freedom to experiment and a wider margin for failure.",{"type":25,"tag":26,"props":1548,"children":1549},{},[1550,1552,1557,1559,1564,1566,1571,1573,1578],{"type":30,"value":1551},"This site and the seven-file split are my hedge against two extremes: an ",{"type":25,"tag":417,"props":1553,"children":1554},{},[1555],{"type":30,"value":1556},"opaque monolith",{"type":30,"value":1558}," of instructions, and ",{"type":25,"tag":417,"props":1560,"children":1561},{},[1562],{"type":30,"value":1563},"implicit knowledge",{"type":30,"value":1565}," that lives only in model context. When something works or breaks, I want a ",{"type":25,"tag":417,"props":1567,"children":1568},{},[1569],{"type":30,"value":1570},"stable pointer",{"type":30,"value":1572},"—a Soul file for voice, Memory for consolidated facts, Tools for what the agent may touch. The blog adds ",{"type":25,"tag":417,"props":1574,"children":1575},{},[1576],{"type":30,"value":1577},"narrative",{"type":30,"value":1579},": why one trade-off beat another, which assumption failed, and which simplification paid off.",{"type":25,"tag":53,"props":1581,"children":1583},{"id":1582},"what-we-builtand-what-it-gives-you-as-a-reader",[1584],{"type":30,"value":1585},"What we built—and what it gives you as a reader",{"type":25,"tag":26,"props":1587,"children":1588},{},[1589,1591,1596],{"type":30,"value":1590},"Below is a fuller picture of ",{"type":25,"tag":417,"props":1592,"children":1593},{},[1594],{"type":30,"value":1595},"what exists in this repository today",{"type":30,"value":1597},", told from the perspective of someone opening the site for the first time. The goal is context: what you are looking at, and how the pieces relate.",{"type":25,"tag":1599,"props":1600,"children":1602},"h3",{"id":1601},"the-landing-story",[1603],{"type":30,"value":1604},"The landing story",{"type":25,"tag":26,"props":1606,"children":1607},{},[1608,1610,1615,1617,1622,1624,1629,1631,1636,1638,1643,1645,1650],{"type":30,"value":1609},"The home page is deliberately ",{"type":25,"tag":417,"props":1611,"children":1612},{},[1613],{"type":30,"value":1614},"sequenced",{"type":30,"value":1616},", not a single wall of text. It opens with a clear ",{"type":25,"tag":417,"props":1618,"children":1619},{},[1620],{"type":30,"value":1621},"who this is for",{"type":30,"value":1623},"—so you can decide in seconds whether the seven-file idea matches how you work. From there, an ",{"type":25,"tag":417,"props":1625,"children":1626},{},[1627],{"type":30,"value":1628},"architecture map",{"type":30,"value":1630}," shows how Soul, Identity, Agents, User, Memory, Heartbeat, and Tools sit in relation to one another, without pretending the diagram is the whole truth. A ",{"type":25,"tag":417,"props":1632,"children":1633},{},[1634],{"type":30,"value":1635},"files grid",{"type":30,"value":1637}," introduces each file on its own card: what it is for, what “good” looks like, and how it connects to the rest. Further down, a ",{"type":25,"tag":417,"props":1639,"children":1640},{},[1641],{"type":30,"value":1642},"session loop",{"type":30,"value":1644}," section frames how I think about starting and closing a working session with an agent, and a ",{"type":25,"tag":417,"props":1646,"children":1647},{},[1648],{"type":30,"value":1649},"quick start",{"type":30,"value":1651}," strips the path down to a handful of concrete steps.",{"type":25,"tag":26,"props":1653,"children":1654},{},[1655,1657,1662],{"type":30,"value":1656},"Each block is implemented as its own Vue component, not because frameworks demand it, but because ",{"type":25,"tag":417,"props":1658,"children":1659},{},[1660],{"type":30,"value":1661},"the same modularity I want in agent design",{"type":30,"value":1663}," is easier to maintain when the site mirrors it. If you only need a fragment of the idea, you can still orient yourself without reading the entire vertical page in one pass.",{"type":25,"tag":1599,"props":1665,"children":1667},{"id":1666},"documentation-you-can-lift-into-your-workflow",[1668],{"type":30,"value":1669},"Documentation you can lift into your workflow",{"type":25,"tag":26,"props":1671,"children":1672},{},[1673,1675,1683,1685,1690,1692,1697],{"type":30,"value":1674},"The ",{"type":25,"tag":417,"props":1676,"children":1677},{},[1678],{"type":25,"tag":195,"props":1679,"children":1681},{"className":1680},[],[1682],{"type":30,"value":1473},{"type":30,"value":1684}," route is where the seven starter files move from concept to ",{"type":25,"tag":417,"props":1686,"children":1687},{},[1688],{"type":30,"value":1689},"something you can actually use",{"type":30,"value":1691},". The content is grounded in the same Markdown sources that ship as ",{"type":25,"tag":417,"props":1693,"children":1694},{},[1695],{"type":30,"value":1696},"downloadable templates",{"type":30,"value":1698},": you are not reading a paraphrase that drifted from the files—you are seeing the spec that can live in your repo or in your agent’s context.",{"type":25,"tag":26,"props":1700,"children":1701},{},[1702,1704,1710,1712,1723,1725,1730,1732,1737,1739,1744,1746,1751],{"type":30,"value":1703},"Those canonical files start in ",{"type":25,"tag":195,"props":1705,"children":1707},{"className":1706},[],[1708],{"type":30,"value":1709},"templates\u002F",{"type":30,"value":1711}," and are ",{"type":25,"tag":417,"props":1713,"children":1714},{},[1715,1717],{"type":30,"value":1716},"mirrored into ",{"type":25,"tag":195,"props":1718,"children":1720},{"className":1719},[],[1721],{"type":30,"value":1722},"public\u002Ftemplates\u002F",{"type":30,"value":1724}," during the build, so every ",{"type":25,"tag":195,"props":1726,"children":1728},{"className":1727},[],[1729],{"type":30,"value":1454},{"type":30,"value":1731}," you see documented has a ",{"type":25,"tag":417,"props":1733,"children":1734},{},[1735],{"type":30,"value":1736},"stable URL",{"type":30,"value":1738}," you can share, fetch, or save. A ",{"type":25,"tag":417,"props":1740,"children":1741},{},[1742],{"type":30,"value":1743},"reading map",{"type":30,"value":1745}," bundled with the templates helps someone new answer “what do I read first?” without guessing order. For me, that separation matters: documentation should be ",{"type":25,"tag":417,"props":1747,"children":1748},{},[1749],{"type":30,"value":1750},"portable and diffable",{"type":30,"value":1752},", not trapped inside a CMS or a proprietary editor.",{"type":25,"tag":1599,"props":1754,"children":1756},{"id":1755},"this-blog-context-on-top-of-the-spec",[1757],{"type":30,"value":1758},"This blog: context on top of the spec",{"type":25,"tag":26,"props":1760,"children":1761},{},[1762,1764,1769,1771,1776,1778,1783],{"type":30,"value":1763},"Longer writing lives here—",{"type":25,"tag":417,"props":1765,"children":1766},{},[1767],{"type":30,"value":1768},"first-person, dated, tagged",{"type":30,"value":1770},", and searchable from the blog index. Where the landing sells the shape of the system and ",{"type":25,"tag":195,"props":1772,"children":1774},{"className":1773},[],[1775],{"type":30,"value":1473},{"type":30,"value":1777}," carries the files themselves, these posts carry ",{"type":25,"tag":417,"props":1779,"children":1780},{},[1781],{"type":30,"value":1782},"intent, mistakes, and follow-ups",{"type":30,"value":1784},". You might come for the templates and stay for a note on memory patterns; or you might read a post first and only then open Soul.md. Either direction is valid.",{"type":25,"tag":26,"props":1786,"children":1787},{},[1788,1790,1795,1797,1802,1804,1809],{"type":30,"value":1789},"Posts are written in ",{"type":25,"tag":417,"props":1791,"children":1792},{},[1793],{"type":30,"value":1794},"Markdown with structured metadata",{"type":30,"value":1796}," (title, summary, date, tags, optional cover image). Some pieces may carry a short ",{"type":25,"tag":417,"props":1798,"children":1799},{},[1800],{"type":30,"value":1801},"author note",{"type":30,"value":1803}," at the top when a personal framing helps; others stay neutral. Drafts can exist while I am still thinking out loud, without appearing in the public index until they are ready—so what you see listed is deliberately ",{"type":25,"tag":417,"props":1805,"children":1806},{},[1807],{"type":30,"value":1808},"published",{"type":30,"value":1810},", not accidental scratch work.",{"type":25,"tag":1599,"props":1812,"children":1814},{"id":1813},"scripts-assets-and-the-small-things-that-make-sharing-work",[1815],{"type":30,"value":1816},"Scripts, assets, and the small things that make sharing work",{"type":25,"tag":26,"props":1818,"children":1819},{},[1820,1822,1827,1829,1834,1836,1841,1843,1848],{"type":30,"value":1821},"Behind the scenes, ",{"type":25,"tag":417,"props":1823,"children":1824},{},[1825],{"type":30,"value":1826},"build scripts",{"type":30,"value":1828}," keep the template set in sync with the public copy and ",{"type":25,"tag":417,"props":1830,"children":1831},{},[1832],{"type":30,"value":1833},"generate a raster social image",{"type":30,"value":1835}," from the site’s vector artwork, so when a link is shared it still looks like ",{"type":25,"tag":103,"props":1837,"children":1838},{},[1839],{"type":30,"value":1840},"this",{"type":30,"value":1842}," project—not a blank or generic preview. None of that changes how you read the pages, but it is part of what makes the repository ",{"type":25,"tag":417,"props":1844,"children":1845},{},[1846],{"type":30,"value":1847},"shippable as a real site",{"type":30,"value":1849},", not only a folder of notes.",{"type":25,"tag":53,"props":1851,"children":1852},{"id":1113},[1853],{"type":30,"value":1116},{"type":25,"tag":26,"props":1855,"children":1856},{},[1857,1859],{"type":30,"value":1858},"Later posts will go deeper: memory patterns, tool boundaries, OpenClaw session notes, lessons from Resizes, and experiments that did not pan out. If anything here helps you—or you believe a premise is wrong—I would welcome a message or a public thread where that conversation belongs. ",{"type":25,"tag":417,"props":1860,"children":1861},{},[1862],{"type":30,"value":1863},"Living documentation works best with a little dialogue around it.",{"type":25,"tag":49,"props":1865,"children":1866},{},[],{"type":25,"tag":26,"props":1868,"children":1869},{},[1870,1872,1877],{"type":30,"value":1871},"Thank you for ",{"type":25,"tag":417,"props":1873,"children":1874},{},[1875],{"type":30,"value":1876},"opening the site, reading this far, and taking an interest in what I have built",{"type":30,"value":1878},". Consider this first post an open door: a work in progress, a point of view under revision, and an invitation to continue the conversation.",{"type":25,"tag":26,"props":1880,"children":1881},{},[1882],{"type":25,"tag":417,"props":1883,"children":1884},{},[1885],{"type":30,"value":1886},"I will see you in the next one.",{"title":8,"searchDepth":1143,"depth":1143,"links":1888},[1889,1890,1891,1898],{"id":1243,"depth":1143,"text":1246},{"id":1511,"depth":1143,"text":1514},{"id":1582,"depth":1143,"text":1585,"children":1892},[1893,1895,1896,1897],{"id":1601,"depth":1894,"text":1604},3,{"id":1666,"depth":1894,"text":1669},{"id":1755,"depth":1894,"text":1758},{"id":1813,"depth":1894,"text":1816},{"id":1113,"depth":1143,"text":1116},"content:posts:welcome.md","posts\u002Fwelcome.md","posts\u002Fwelcome",1778862828869]