ข้ามไปยังเนื้อหา

Workflow หลาย Repository

ผู้อ่าน: ผู้ดูแลโปรเจกต์และ agent ที่ได้รับอนุญาตให้ตั้งค่า หากต้องการใช้งานตามปกติ เริ่มที่ เริ่มใช้งาน

ใช้คู่มือนี้เมื่อ change หนึ่งเขียนโค้ดในหลาย repository หรือเมื่อ test รันจาก repository หนึ่งแต่ต้องใช้โค้ดหรือ contract จาก repository อื่น

ถ้า change ใช้ repository เดียว ให้หยุดตรงนี้แล้วทำตาม เริ่มใช้งาน ซึ่งเป็นเส้นทางที่สั้นกว่า

โปรเจกต์ประกาศ repository ที่ใช้ได้ change เลือกว่าจะเขียนหรืออ่านตัวไหน และ proof ชุดเดียวกับ Land ครั้งเดียวครอบทั้งหมด

คุณขอให้เพิ่มฟิลด์ใหม่ในหน้าโปรไฟล์ repository ของ API ต้องส่งฟิลด์นั้นกลับมา และ repository ของ web ต้องแสดงผล ส่วน repository contracts ที่ใช้ร่วมกันอธิบายรูปแบบ response และห้ามแก้

การตัดสินใจ: ประกาศ scope ก่อน ก่อน Build ให้บอก (หรือยืนยัน) ว่า change นี้ เขียน repository ไหนได้ (api, app) อ่านอย่างเดียว ตัวไหน (contracts) และอะไร ต้องมาก่อน (api ก่อน app) Change Loop จะไม่แตะ ไม่ใช้ทดสอบ และไม่ส่งมอบ repository ที่อยู่นอกการประกาศนี้

สิ่งที่คุณเห็น:

  • agent สรุป scope ก่อนที่คุณจะอนุมัติ: repository ที่เขียน repository ที่อ่าน และลำดับ
  • ความคืบหน้าของ Build และ Prove แยกตาม repository check ของ web รันกับโค้ดใหม่ของ API ที่ยังไม่ส่งมอบ เพราะทั้งคู่อยู่ใน sandbox ที่แยกกัน
  • ผลสุดท้ายที่ระบุว่า repository ใดถูกอ่าน เขียน พิสูจน์แล้ว และยังรอ Land

สิ่งที่คุณตัดสินใจ:

  1. ยืนยัน scope และลำดับของ repository (การตัดสินใจสำคัญข้อเดียว)
  2. อนุมัติข้อตกลง เหมือน change ทั่วไป
  3. สั่ง /land ครั้งเดียว ทุก repository ที่เขียนได้จะได้รับการเปลี่ยนแปลงเป็น diff ที่ยังไม่ commit; Git HEAD และ index ไม่เปลี่ยนในทุก repository ให้ตรวจ diff ของแต่ละตัวแล้ว commit ตามขั้นตอน Git ปกติ จบจริงเมื่อเป็น archived เท่านั้น proven ยังไม่นับ

ถ้า repository ที่อ่านขยับระหว่างทำงาน agent จะ sync และ prove ใหม่เอง คุณไม่ต้องรัน คำสั่ง sandbox หรือ sync

ส่วนต่อจากนี้คือกลไกที่ agent และผู้ดูแลโปรเจกต์ใช้

ไฟล์เหล่านี้ตอบคนละคำถาม และต้องตั้งค่าตามลำดับ:

ลำดับ Contract คำถามที่ตอบ
1 openspec/repositories.yaml โปรเจกต์นี้ใช้ repository อะไรได้บ้าง
2 openspec/changes/<change>/repositories.yaml change นี้อ่านหรือเขียนตัวไหนได้บ้าง
3 derived provider หรือฟิลด์ใน conditional execution.yaml command หลักฐานตัวนี้ต้องใช้ repository อะไรบ้าง

อย่าข้ามไปต่อ provider ก่อน เพราะ provider พิสูจน์ repository ที่ topology ไม่รู้จัก หรือ change ไม่ได้เลือกไม่ได้

เพิ่มทุก repository ที่ Change Loop อาจต้องแยกพื้นที่ใน openspec/repositories.yaml:

{
"version": 1,
"repositories": [
{ "id": "api", "path": "services/api", "setupCommand": "npm ci" },
{ "id": "app", "path": "apps/web", "setupCommand": "npm ci" },
{ "id": "contracts", "path": "contracts", "mode": "read" },
{
"id": "partner-sdk",
"type": "external",
"path": "../partner-sdk",
"mode": "read",
"allowOutsideRoot": true
}
]
}

สิ่งที่ต้องรู้:

  • id คือชื่อคงที่ที่ task, provider, receipt และ Land ใช้ร่วมกัน
  • path อิงจาก control repository
  • setupCommand เตรียม worktree ใหม่ของ repository นั้น
  • path นอก control repository เช่น sibling ../sdk ต้องมี allowOutsideRoot: true ส่วน type จะคงเป็น git (ค่าเริ่มต้น) หรือใช้ external ก็ได้ ทำงานเหมือนกัน sibling ที่เขียนได้เป็นเจ้าของ task และ Land เหมือน submodule
  • repository ที่ถูกเลือกทุกตัวต้อง initialize Git แล้ว

Change Loop ปฏิเสธ dependency ที่ไม่ใช่ Git เพราะมันล็อก commit และแยก directory ที่กำลังขยับอย่างตรงไปตรงมาไม่ได้

ตรวจก่อนสร้าง change:

Terminal window
claude-foundation repos

ใน change ให้เลือกเฉพาะ repository ที่ต้องใช้:

{
"version": 1,
"repositories": [
{ "id": "api", "mode": "write", "dependsOn": [] },
{ "id": "app", "mode": "write", "dependsOn": ["api"] },
{ "id": "contracts", "mode": "read", "dependsOn": [] },
{ "id": "partner-sdk", "mode": "read", "dependsOn": [] }
]
}

ใช้ write เฉพาะ repository ที่ change จะสร้างโค้ด ใช้ read กับ test data, contract, SDK และ integration dependency repository แบบ read เป็นส่วนหนึ่งของ identity ของ proof แต่ไม่ใช่เป้าหมาย Build หรือ Land

การเลือก non-root ตัวใดก็ตามทำให้ lifecycle เป็น composite รวมถึงกรณีเลือก child เพียงตัวเดียวโดยไม่มี product work ใน root; ระบบต้องไม่ลดรูปไปใช้ Apply หรือ archive แบบ single-root

ตรวจ selection ที่ resolve แล้ว:

Terminal window
claude-foundation repos <change>

task implementation ทุกตัวต้องระบุ repository เจ้าของและ path ส่วน dependency ทำให้ลำดับข้าม repository ชัดเจน:

- [ ] **T001** Update API [repo:api] [kind:implementation] [paths:src/profile]
- [ ] **T002** Update app [repo:app] [kind:implementation] [depends:T001] [paths:src/profile]
- [ ] **T003** Verify contract [repo:app] [kind:contract] [depends:T001,T002]

Change Loop compile repository selection, task, provider และลำดับ Land เป็น execution graph ให้เอง ไม่ต้องสร้างไฟล์ graph ที่สอง

คำสั่งปกติของ agent สร้าง workspace ที่เลือกพร้อมกัน:

Terminal window
claude-foundation advance <change> --through build

sandbox create --all และ sandbox inspect ยังเป็น operator diagnostic ใต้ help --all; ผู้ใช้ไม่ต้องเรียงคำสั่งเอง

หลัง isolation child ที่เลือกทุกตัวต้องมี runtime record ซึ่ง target, access mode, base head และ worktree ตรงกับ catalog sandbox inspect จะแสดง missing-record, unexpected-record, missing หรือ invalid แทนการนำ target checkout มาใช้เงียบ ๆ การ inspect อ่าน filesystem และ Git metadata โดยตรง จึงไม่รัน git ที่ repository ควบคุมผ่าน PATH

repository แบบ write ได้ Build worktree แยก ส่วน read และ external ที่มี Git ได้ detached worktree ที่ล็อก commit คำสั่งนี้ไม่ได้ทำให้ service ภายนอกหรือ directory ทั่วไปปลอดภัย sandbox เป็น Git workspace isolation ไม่ใช่ OS security boundary

โค้ดและ test ของ root ยังใช้ nested repository ผ่าน path ใต้ root ได้ เช่น require('./packages/lib') ใน root sandbox Harness จะ link path ของ repository ที่เลือกไปยัง sandbox ของ repository นั้น check ของ root จึงเห็นงานที่ยังไม่ commit และการแก้ผ่าน path ใดก็ไปลงที่เดียวกัน ส่วน nested repository ที่ไม่ได้เลือกจะเป็น commit ที่ gitlink ของ root บันทึกไว้ checkout จาก object ในเครื่องแม้ target ไม่เคย initialize submodule นั้น และเป็นแบบอ่านอย่างเดียว path เหล่านี้ไม่ใช่ change ของ root จึงไม่อยู่ใน proof, review, changed surface หรือ Land ของ root และไม่มีใคร ต้องสร้าง link หรือ initialize submodule เอง

สำหรับ custom wiring ใน conditional execution.yaml, repository คือ working directory ของ provider ส่วน repositories คือชุดทั้งหมดที่ command อ่าน:

{
"providers": {
"integration": {
"capability": "integration",
"adapter": "command",
"repository": "api",
"repositories": ["api", "app", "contracts", "partner-sdk"],
"command": ["npm", "run", "test:integration"]
}
}
}

Change Loop ส่ง environment สำคัญสองตัว:

  • FOUNDATION_REPOSITORY_ID — ID ของ repository ที่เป็น working directory
  • FOUNDATION_REPOSITORIES_FILE — JSON manifest ที่มี version และ map ID ทุกตัว ใน scope ไปยัง path, access และ baseHead ที่แยกพื้นที่แล้ว

changed-surface check, review packet, provider manifest, snapshot และ Land ใช้ base ที่บันทึกชุดเดียวกัน ก่อน isolation source head ที่เลือกใช้ตั้งต้นได้ แต่หลัง isolation ถ้า child binding หายจะเป็น infrastructure failure

โค้ด provider ต้องอ่าน manifest ห้ามสมมติว่า repository ทั้งห้าของบริษัทถูก checkout เป็น sibling อยู่ในทุกเครื่อง

ชุด repository เป็นส่วนหนึ่งของ command deduplication และ identity ของ receipt คำสั่งเหมือนกันแต่ scope ต่างกันจะรันแยก และ receipt บันทึก repositoryIds ครบ

วางแผน worker ขนานหลัง scope กับ dependency นิ่งแล้วเท่านั้น:

Terminal window
claude-foundation agents plan <change>

ถ้า change อื่นทำให้ repository ที่เลือกขยับ advance จะ sync sandbox เองก่อน Prove ส่วน sandbox sync <change> เป็น primitive สำหรับวินิจฉัยที่อยู่เบื้องหลัง sync refresh child read worktree ได้แม้ control sandbox ใช้ copy mode และรัน setupCommand ของ repository ใหม่หลัง refresh ถ้า setup หรือ provider ทิ้ง tracked change ไว้ใน read workspace readiness จะ fail closed

Terminal window
claude-foundation advance <change> --through proven

proof readiness และ proof run ยังเป็น primitive สำหรับวินิจฉัย Prove รัน branch อิสระขนานกันได้และรักษา branch ที่เสร็จแล้วเมื่ออีก branch ล้ม แต่ aggregate proof ยังต้องตรงกับ repository และ provider scope ปัจจุบันทั้งหมด read dependency ที่ขยับต้อง sync และ prove ใหม่ Change Loop จะไม่รับรอง commit เก่า ใต้ repository manifest ใหม่

Consumer quality ใช้ graph เดียวกันแต่ไม่เฉลี่ยคะแนนข้าม repository ต้องเพิ่ม ทุก repository ที่ถูกเลือกไว้ใน quality/foundation-quality.json; ถ้าขาดตัวใด ระบบจะ fail closed แต่ละ lane เก็บ commit, workspace digest, tool/config identity, baseline และ assurance แยกกัน รัน quality run --change <change> ก่อน Prove หรือให้ evidence bootstrap ต่อ quality config ที่ commit แล้วเป็น static-analysis evidence ดูรายละเอียดที่ Quality gate ของโปรเจกต์

read repository ไม่มี Land node และผู้ใช้ให้อำนาจ local delivery ทั้ง transaction ด้วยคำสั่งเดียว:

/land <change>

Harness เตรียม writable target ทุกตัวก่อนเขียนไฟล์แรก แล้ว apply projection ที่ พิสูจน์แล้วตาม dependency พร้อม durable checkpoint แต่ละ node จบที่ applied-uncommitted; Git HEAD กับ index ของทุก repository ไม่เปลี่ยน และงานเดิม ที่ไม่ overlap ยังคงอยู่ เรียก /land ซ้ำแล้วระบบ resume transaction เดิมโดยข้าม node ที่ตรวจแล้ว land check, land record แบบ legacy และ land resume ยังเป็น diagnostic/compatibility primitive ไม่ใช่ขั้นที่ user ต้องเรียงเอง ส่วน commit, push และ PR อยู่นอก Land และต้องมีอำนาจแยก

saga นี้ใช้ด้วยเมื่อเลือก non-root child เพียงตัวเดียว runtime record ที่หายต้องไม่ ทำให้ Land ลัดไปใช้ทาง single-repository

เหตุการณ์ Action ที่ถูกต้อง
target ที่เลือกขยับ advance sync sandbox และ Prove ใหม่เอง
sync เจอ replay conflict agent แก้ path ที่ระบุใน sandbox ไม่ต้องสร้าง change ใหม่
read repository สกปรก เอา mutation ออกหรือแก้ setup/provider
setup ของ repository ล้ม Harness retry เฉพาะ repository นั้นและเก็บ sibling ที่พร้อมแล้ว; แก้ policy เฉพาะเมื่อ command ที่ประกาศผิดจริง
binding ของ child ที่เลือกหาย Harness ซ่อม binding โดยรักษา worktree ที่ยังใช้ได้; ใช้ sandbox inspect เมื่อต้องวินิจฉัยเท่านั้น
path มาตรฐานของ child เป็น worktree ของ repository อื่น อย่าแก้หรือลบทิ้ง ตรวจ path ที่รายงาน แล้วแก้ conflict ของ target/path หรือ abandon change อย่างชัดเจน
provider มองไม่เห็น repository เพิ่มใน repositories ของ provider ห้าม hard-code local path
check ปฏิเสธเพราะสำเนาใน root ของ repository ที่ไม่ได้เลือกถูกแก้ คืนสำเนานั้น (ข้อความปฏิเสธระบุคำสั่งไว้) หรือเลือก repository ผ่าน semantic amendment
Land ถูกขัดจังหวะ เรียก /land <change> ซ้ำเพื่อ resume journal; งานใน root หรือ repository sandbox ที่เพิ่มหลัง delivery ก่อนหน้าจะถูก apply ใหม่
Land หยุดด้วย ROOT_POINTER_MOVED root sandbox ขยับ pointer ของ submodule ที่ change เลือกไว้: agent นำ commit เข้า sandbox ของ repository นั้น คืน root pointer เป็น base แล้ว resume
Land หยุดด้วย repository-pointer-change root sandbox ขยับ pointer ของ submodule ที่ไม่ได้เลือก: ให้ user เลือกว่าจะส่ง pointer ผ่าน repository นั้น, คืน pointer เป็น base แล้ว land ส่วนที่เหลือ หรือ pause

User: ยืนยัน scope/dependency ที่มีผลต่อ behavior, เรียก Land ครั้งเดียว, ตรวจ final diff และ commit ตาม Git process ของ project ไม่ต้องสร้าง manifest, grant, receipt, hash หรือ Land journal เอง

Agent: ตั้งค่า scope สามชั้นตามลำดับ ใช้ path จาก manifest รัน readiness ก่อน เสียรอบ Prove ทำ recovery ตามที่ระบบรายงาน และสรุปว่า repository ใดถูกอ่าน เขียน พิสูจน์แล้ว หรือยังรอ Land ห้ามให้ user คัดลอก protocol JSON และห้ามลด test ที่ต้อง ใช้ห้า repository เหลือสามตัวเพียงเพราะ sandbox มีข้อมูลไม่ครบ