Agent Skills
› uw-syfi/vibesys
› change-module-graph
change-module-graph
GitHub管理仓库模块图,处理Python模块、TS包及I/O接口的添加、拆分与连接。用于解决tach检查失败、跨模块导入或架构违规问题。
Trigger Scenarios
创建或拆分Python模块/库
添加跨模块导入或tach边
声明模块公共接口
tach或包图检查失败
Install
npx skills add uw-syfi/vibesys --skill change-module-graph -g -y
SKILL.md
Frontmatter
{
"name": "change-module-graph",
"metadata": {
"kind": "codebase"
},
"description": "Add, split, move or reconnect modules in this repository's module graph (Python modules and libraries declared in tach.toml, TypeScript client packages), and add I\/O interfaces and their implementations. Use when creating or splitting a Python module, library or client package, adding a cross-module import or tach edge, declaring a module's public interface, adding an interface or implementation to an I\/O library, placing an agent tool server, or when a size limit, tach, or the package-graph check fails."
}
Change the module graph
The software-design skill says why modules are deep, declared and one-way.
This skill says how that is declared and checked here. Open
references/python.md for tach, the I/O libraries, tool
servers, Python idioms and golden examples, and
references/typescript.md for the client package
graph.
Builds on
software-design: rules 2 (declared interfaces), 3 (substitutability), 4 (one-way dependencies), 5 (factor when callers need internals) and 14 (functional core, interfaces and implementations).enforce-rules: when a graph rule should become a check.
When this applies
- A new, split or moved Python module or library, or a new TypeScript client package.
- A new import that crosses modules or packages.
- A new I/O interface, or a new implementation of one.
- Placing an agent tool server.
check_tach, the package-graph check, or a size limit fails.
Steps
- Place code by ownership. Put it in the module or library that owns the responsibility, or a new one, never where similar code happens to sit; the layout and placement rule are in architecture.md. Unenforced: ownership needs judgment.
- Declare every Python module and its interface in
tach.toml. A module needs a[[modules]]entry; a library also needs itssource_rootsentry and an[[interfaces]]entry exposing onlyapi; a new or split product module adds an[[interfaces]]entry too.check_tachfails on an undeclared edge or a cycle. - Add the edge in the same PR as the import, never upward and never
closing a cycle; prefer removing an edge. Then regenerate the graph in
architecture.md with
check_tach_graph --write;check_tach_graph --checkfails on drift.test_the_libraries_import_each_other_without_a_cyclealso rejects cycles between whole libraries that tach's module edges miss. - Import a library only through
<pkg>.api, and core only throughvibesys.api. Thetach.tomlinterfaces enforce the first, andcheck_tachfails on aheadlesstoserverimport or the reverse.test_lower_libraries_do_not_discover_the_vibesys_product_dynamicallyfails if a lower library reaches the product by dynamic import. - Keep the core pure.
vs_coreimports no I/O library; its I/O goes through interfaces the shell calls.check_purityholds the core to it with a shrink-only allowlist. - Name interfaces by role and implementations
<Variant><Role>, put the interface in its owning library's.api, and register every implementation in that library's contract suite. Unenforced: no check maps interfaces to contract suites or names to roles yet. - Use the repository's vocabulary. "protocol" means a wire protocol
(
vs-evaluator-protocol), "provider" an agent CLI vendor, "driver" an agent driver invs-agent, and "agent backend" the choice between running the real CLI and a stub; do not reuse these words for interfaces, and rename an outlier that borrows one when you touch it. Unenforced: term choice needs judgment. - Declare a TypeScript package's layer and exports in its
package.json.check_package_graphowns the rules between packages and the dependency-cruiser ruleworkspace-packages-use-public-exportsrejects relative paths into another package; runpnpm check:ts-architecturefirst, since each gate names what a new package is missing. - Treat a size limit as a cue to factor, not a target to dodge.
check_file_length, RuffC901andPLR0912, and Biome'snoExcessiveLinesPerFilehold the numbers.
Testing
- Run
check_tach,check_tach_graph(with--check) and./scripts/check_lint.shafter any Python graph change. - Run
pnpm check:ts-architectureandpnpm check:knipfrom the clients workspace after any TypeScript package change. - Run the new interface's contract suite against every implementation,
Fake and production, as the
write-vibesys-testsskill describes. Unenforced: real implementations run only when opted in.
Known failure modes
- A new library escapes the public-surface test, which lists library
apimodules by hand, so add the new one to that list;test_library_public_exports_resolvefails only for libraries it lists. - A product module without an
[[interfaces]]entry exposes all of its internals to any module with the edge, and later code grows to depend on them. Unenforced: existing modules are not yet declared, so a check would fail on all of them. - A cycle through three libraries passes tach because no single module edge
closes it;
test_the_libraries_import_each_other_without_a_cycleexists for that reason. - Code that rebuilds
.vibesyspaths instead of opening them throughvs_project.api.Project;test_physical_configuration_root_is_private_to_project_libraryfails on it.
Sources of truth
tach.toml: Python modules, edges and interfaces.- architecture.md: the layout, the placement rule and the generated module graph.
- clients-architecture.md: the client package graph and state rules.
- The package-graph check: the TypeScript package rules.
Version History
- 256ebe6 Current 2026-10-18 21:28


