mars-agents 0.0.3__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.
Files changed (62) hide show
  1. mars_agents-0.0.3/.github/workflows/ci.yml +39 -0
  2. mars_agents-0.0.3/.github/workflows/release.yml +270 -0
  3. mars_agents-0.0.3/.gitignore +6 -0
  4. mars_agents-0.0.3/AGENTS.md +152 -0
  5. mars_agents-0.0.3/CLAUDE.md +152 -0
  6. mars_agents-0.0.3/Cargo.lock +1431 -0
  7. mars_agents-0.0.3/Cargo.toml +40 -0
  8. mars_agents-0.0.3/LICENSE +21 -0
  9. mars_agents-0.0.3/PKG-INFO +85 -0
  10. mars_agents-0.0.3/README.md +68 -0
  11. mars_agents-0.0.3/npm/.gitignore +4 -0
  12. mars_agents-0.0.3/npm/@haowjy/mars-agents/bin/mars +44 -0
  13. mars_agents-0.0.3/npm/@haowjy/mars-agents/package.json +23 -0
  14. mars_agents-0.0.3/npm/@haowjy/mars-agents-darwin-arm64/package.json +13 -0
  15. mars_agents-0.0.3/npm/@haowjy/mars-agents-darwin-x64/package.json +13 -0
  16. mars_agents-0.0.3/npm/@haowjy/mars-agents-linux-arm64/package.json +14 -0
  17. mars_agents-0.0.3/npm/@haowjy/mars-agents-linux-x64/package.json +14 -0
  18. mars_agents-0.0.3/pyproject.toml +25 -0
  19. mars_agents-0.0.3/scripts/release.sh +187 -0
  20. mars_agents-0.0.3/src/cli/add.rs +239 -0
  21. mars_agents-0.0.3/src/cli/cache.rs +182 -0
  22. mars_agents-0.0.3/src/cli/check.rs +367 -0
  23. mars_agents-0.0.3/src/cli/doctor.rs +212 -0
  24. mars_agents-0.0.3/src/cli/init.rs +219 -0
  25. mars_agents-0.0.3/src/cli/link.rs +790 -0
  26. mars_agents-0.0.3/src/cli/list.rs +186 -0
  27. mars_agents-0.0.3/src/cli/mod.rs +343 -0
  28. mars_agents-0.0.3/src/cli/outdated.rs +167 -0
  29. mars_agents-0.0.3/src/cli/output.rs +418 -0
  30. mars_agents-0.0.3/src/cli/override_cmd.rs +42 -0
  31. mars_agents-0.0.3/src/cli/remove.rs +34 -0
  32. mars_agents-0.0.3/src/cli/rename.rs +51 -0
  33. mars_agents-0.0.3/src/cli/repair.rs +104 -0
  34. mars_agents-0.0.3/src/cli/resolve_cmd.rs +95 -0
  35. mars_agents-0.0.3/src/cli/sync.rs +41 -0
  36. mars_agents-0.0.3/src/cli/upgrade.rs +35 -0
  37. mars_agents-0.0.3/src/cli/why.rs +133 -0
  38. mars_agents-0.0.3/src/config/mod.rs +703 -0
  39. mars_agents-0.0.3/src/discover/mod.rs +653 -0
  40. mars_agents-0.0.3/src/error.rs +278 -0
  41. mars_agents-0.0.3/src/frontmatter/mod.rs +273 -0
  42. mars_agents-0.0.3/src/fs/mod.rs +405 -0
  43. mars_agents-0.0.3/src/hash/mod.rs +217 -0
  44. mars_agents-0.0.3/src/lib.rs +15 -0
  45. mars_agents-0.0.3/src/lock/mod.rs +524 -0
  46. mars_agents-0.0.3/src/main.rs +6 -0
  47. mars_agents-0.0.3/src/manifest/mod.rs +188 -0
  48. mars_agents-0.0.3/src/merge/mod.rs +359 -0
  49. mars_agents-0.0.3/src/resolve/mod.rs +2009 -0
  50. mars_agents-0.0.3/src/source/git.rs +907 -0
  51. mars_agents-0.0.3/src/source/mod.rs +101 -0
  52. mars_agents-0.0.3/src/source/parse.rs +521 -0
  53. mars_agents-0.0.3/src/source/path.rs +152 -0
  54. mars_agents-0.0.3/src/sync/apply.rs +941 -0
  55. mars_agents-0.0.3/src/sync/diff.rs +595 -0
  56. mars_agents-0.0.3/src/sync/mod.rs +1124 -0
  57. mars_agents-0.0.3/src/sync/plan.rs +408 -0
  58. mars_agents-0.0.3/src/sync/target.rs +1180 -0
  59. mars_agents-0.0.3/src/types.rs +343 -0
  60. mars_agents-0.0.3/src/validate/mod.rs +322 -0
  61. mars_agents-0.0.3/tests/cli_integration.rs +4 -0
  62. mars_agents-0.0.3/tests/integration/mod.rs +1231 -0
@@ -0,0 +1,39 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main, master]
6
+ pull_request:
7
+
8
+ env:
9
+ CARGO_TERM_COLOR: always
10
+
11
+ jobs:
12
+ check:
13
+ name: Check (${{ matrix.rust }})
14
+ runs-on: ubuntu-latest
15
+ strategy:
16
+ matrix:
17
+ rust: [stable, nightly]
18
+
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+
22
+ - uses: dtolnay/rust-toolchain@master
23
+ with:
24
+ toolchain: ${{ matrix.rust }}
25
+ components: rustfmt, clippy
26
+
27
+ - uses: Swatinem/rust-cache@v2
28
+
29
+ - name: Build
30
+ run: cargo build
31
+
32
+ - name: Test
33
+ run: cargo test
34
+
35
+ - name: Clippy
36
+ run: cargo clippy -- -D warnings
37
+
38
+ - name: Format check
39
+ run: cargo fmt --check
@@ -0,0 +1,270 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags: ["v*"]
6
+
7
+ env:
8
+ CARGO_TERM_COLOR: always
9
+
10
+ jobs:
11
+ build:
12
+ name: Build (${{ matrix.target }})
13
+ runs-on: ${{ matrix.runner }}
14
+ strategy:
15
+ matrix:
16
+ include:
17
+ - target: x86_64-unknown-linux-gnu
18
+ runner: ubuntu-latest
19
+ artifact: mars-linux-x64
20
+ - target: aarch64-unknown-linux-gnu
21
+ runner: ubuntu-latest
22
+ artifact: mars-linux-arm64
23
+ - target: aarch64-apple-darwin
24
+ runner: macos-latest
25
+ artifact: mars-darwin-arm64
26
+ - target: x86_64-apple-darwin
27
+ runner: macos-15-intel
28
+ artifact: mars-darwin-x64
29
+ steps:
30
+ - uses: actions/checkout@v4
31
+
32
+ - uses: dtolnay/rust-toolchain@stable
33
+ with:
34
+ targets: ${{ matrix.target }}
35
+
36
+ - uses: Swatinem/rust-cache@v2
37
+ with:
38
+ key: ${{ matrix.target }}
39
+
40
+ - name: Install Linux ARM64 cross toolchain
41
+ if: matrix.target == 'aarch64-unknown-linux-gnu'
42
+ run: |
43
+ sudo apt-get update
44
+ sudo apt-get install -y gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu
45
+
46
+ - name: Build
47
+ if: matrix.target != 'aarch64-unknown-linux-gnu'
48
+ run: cargo build --release --target ${{ matrix.target }}
49
+
50
+ - name: Build (Linux ARM64)
51
+ if: matrix.target == 'aarch64-unknown-linux-gnu'
52
+ env:
53
+ CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
54
+ run: cargo build --release --target ${{ matrix.target }}
55
+
56
+ - name: Strip binary
57
+ if: matrix.target != 'aarch64-unknown-linux-gnu'
58
+ run: strip target/${{ matrix.target }}/release/mars
59
+
60
+ - name: Strip binary (Linux ARM64)
61
+ if: matrix.target == 'aarch64-unknown-linux-gnu'
62
+ run: aarch64-linux-gnu-strip target/${{ matrix.target }}/release/mars
63
+
64
+ - name: Rename binary
65
+ run: cp target/${{ matrix.target }}/release/mars ${{ matrix.artifact }}
66
+
67
+ - uses: actions/upload-artifact@v4
68
+ with:
69
+ name: ${{ matrix.artifact }}
70
+ path: ${{ matrix.artifact }}
71
+
72
+ pypi-wheels:
73
+ name: Build PyPI wheels (${{ matrix.target }})
74
+ runs-on: ${{ matrix.runner }}
75
+ strategy:
76
+ matrix:
77
+ include:
78
+ - target: x86_64-unknown-linux-gnu
79
+ runner: ubuntu-latest
80
+ artifact: wheels-linux-x64
81
+ - target: aarch64-unknown-linux-gnu
82
+ runner: ubuntu-24.04-arm
83
+ artifact: wheels-linux-arm64
84
+ - target: aarch64-apple-darwin
85
+ runner: macos-latest
86
+ artifact: wheels-darwin-arm64
87
+ - target: x86_64-apple-darwin
88
+ runner: macos-15-intel
89
+ artifact: wheels-darwin-x64
90
+ steps:
91
+ - uses: actions/checkout@v4
92
+
93
+ - name: Build wheels
94
+ uses: PyO3/maturin-action@v1
95
+ with:
96
+ command: build
97
+ target: ${{ matrix.target }}
98
+ manylinux: auto
99
+ args: --release --out dist
100
+
101
+ - uses: actions/upload-artifact@v4
102
+ with:
103
+ name: ${{ matrix.artifact }}
104
+ path: dist/*.whl
105
+
106
+ pypi-sdist:
107
+ name: Build PyPI sdist
108
+ runs-on: ubuntu-latest
109
+ steps:
110
+ - uses: actions/checkout@v4
111
+
112
+ - name: Build sdist
113
+ uses: PyO3/maturin-action@v1
114
+ with:
115
+ command: sdist
116
+ args: --out dist
117
+
118
+ - uses: actions/upload-artifact@v4
119
+ with:
120
+ name: sdist
121
+ path: dist/*.tar.gz
122
+
123
+ pypi-publish:
124
+ name: Publish PyPI
125
+ needs: [pypi-wheels, pypi-sdist]
126
+ runs-on: ubuntu-latest
127
+ environment: pypi
128
+ permissions:
129
+ id-token: write
130
+ steps:
131
+ - uses: actions/download-artifact@v4
132
+ with:
133
+ path: dist
134
+ pattern: wheels-*
135
+ merge-multiple: true
136
+
137
+ - uses: actions/download-artifact@v4
138
+ with:
139
+ path: dist
140
+ name: sdist
141
+
142
+ - name: Publish to PyPI
143
+ uses: pypa/gh-action-pypi-publish@release/v1
144
+ with:
145
+ packages-dir: dist
146
+
147
+ github-release:
148
+ name: GitHub Release
149
+ needs: build
150
+ runs-on: ubuntu-latest
151
+ permissions:
152
+ contents: write
153
+ steps:
154
+ - uses: actions/checkout@v4
155
+
156
+ - uses: actions/download-artifact@v4
157
+ with:
158
+ path: artifacts/
159
+ merge-multiple: true
160
+
161
+ - name: Create release
162
+ uses: softprops/action-gh-release@v2
163
+ with:
164
+ generate_release_notes: true
165
+ files: artifacts/mars-*
166
+
167
+ npm-publish:
168
+ name: Publish npm packages
169
+ needs: build
170
+ runs-on: ubuntu-latest
171
+ permissions:
172
+ id-token: write
173
+ steps:
174
+ - uses: actions/checkout@v4
175
+
176
+ - uses: actions/setup-node@v4
177
+ with:
178
+ node-version: "lts/*"
179
+ registry-url: "https://registry.npmjs.org"
180
+
181
+ - name: Ensure npm supports trusted publishing
182
+ run: npm install -g npm@latest
183
+
184
+ - uses: actions/download-artifact@v4
185
+ with:
186
+ path: artifacts/
187
+ pattern: mars-*
188
+ merge-multiple: true
189
+
190
+ - name: Extract version from tag
191
+ id: version
192
+ run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
193
+
194
+ - name: Verify tag matches Cargo.toml
195
+ run: |
196
+ CARGO_VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/')
197
+ TAG_VERSION=${{ steps.version.outputs.version }}
198
+ if [ "$CARGO_VERSION" != "$TAG_VERSION" ]; then
199
+ echo "::error::Tag version ($TAG_VERSION) does not match Cargo.toml ($CARGO_VERSION)"
200
+ exit 1
201
+ fi
202
+
203
+ - name: Prepare and publish platform packages
204
+ run: |
205
+ VERSION=${{ steps.version.outputs.version }}
206
+
207
+ publish_platform() {
208
+ local pkg_dir=$1
209
+ local binary=$2
210
+ local pkg_name
211
+ pkg_name=$(node -e "console.log(require('./$pkg_dir/package.json').name)")
212
+
213
+ # Skip if already published (idempotent on re-run)
214
+ if npm view "$pkg_name@$VERSION" version >/dev/null 2>&1; then
215
+ echo "Skipping $pkg_name@$VERSION — already published"
216
+ return 0
217
+ fi
218
+
219
+ (
220
+ cd "$pkg_dir"
221
+ npm version "$VERSION" --no-git-tag-version --allow-same-version
222
+ cp "$GITHUB_WORKSPACE/artifacts/$binary" mars
223
+ chmod +x mars
224
+ npm publish --provenance --access public
225
+ )
226
+ }
227
+
228
+ publish_platform npm/@haowjy/mars-agents-linux-x64 mars-linux-x64
229
+ publish_platform npm/@haowjy/mars-agents-linux-arm64 mars-linux-arm64
230
+ publish_platform npm/@haowjy/mars-agents-darwin-arm64 mars-darwin-arm64
231
+ publish_platform npm/@haowjy/mars-agents-darwin-x64 mars-darwin-x64
232
+
233
+ - name: Publish CLI stub package
234
+ run: |
235
+ VERSION=${{ steps.version.outputs.version }}
236
+
237
+ # Skip if already published
238
+ if npm view "@haowjy/mars-agents@$VERSION" version >/dev/null 2>&1; then
239
+ echo "Skipping @haowjy/mars-agents@$VERSION — already published"
240
+ exit 0
241
+ fi
242
+
243
+ (
244
+ cd npm/@haowjy/mars-agents
245
+ node -e "
246
+ const pkg = require('./package.json');
247
+ pkg.version = '$VERSION';
248
+ for (const dep of Object.keys(pkg.optionalDependencies || {})) {
249
+ pkg.optionalDependencies[dep] = '$VERSION';
250
+ }
251
+ require('fs').writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');
252
+ "
253
+ npm publish --provenance --access public
254
+ )
255
+
256
+ cargo-publish:
257
+ name: Publish crate
258
+ needs: build
259
+ runs-on: ubuntu-latest
260
+ permissions:
261
+ contents: read
262
+ steps:
263
+ - uses: actions/checkout@v4
264
+
265
+ - uses: dtolnay/rust-toolchain@stable
266
+
267
+ - name: Publish to crates.io
268
+ env:
269
+ CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
270
+ run: cargo publish || true
@@ -0,0 +1,6 @@
1
+ # Rust build artifacts
2
+ /target/
3
+
4
+ # Project-local directories (managed by other tools)
5
+ .meridian/
6
+ .agents/
@@ -0,0 +1,152 @@
1
+ # Development Guide: mars-agents
2
+
3
+ Mars is an agent package manager for `.agents/` directories. It installs agent profiles and skills from git/local sources, tracks ownership in `mars.lock`, and links managed content into tool directories like `.claude/`.
4
+
5
+ ## Core Principles
6
+
7
+ 1. **Resolve first, then act.** Validate + build full desired state before mutating files. If any conflict or error is detected during resolution, zero mutations occur.
8
+ - *Why*: Partial failures leave users in states that are hard to diagnose. A user who sees "3 conflicts" can fix all three and retry. A user whose command half-completed has to figure out what happened first.
9
+
10
+ 2. **Atomic writes.** Config, lock, and installed files use temp + rename. Crash mid-write leaves the old file intact.
11
+ - *Why*: Mars manages files that agents and tools read continuously. A half-written mars.toml breaks every tool that reads it. tmp + rename is atomic on POSIX — no recovery logic needed.
12
+
13
+ 3. **Lock file is authority.** `mars.lock` defines managed ownership and checksums. If it's not in the lock, it's not managed.
14
+ - *Why*: Without a single authority, mars can't distinguish "user added this manually" from "mars installed this." The lock makes ownership explicit — safe coexistence with unmanaged files.
15
+
16
+ 4. **No heuristics.** User intent is expressed through explicit flags and arguments, not inferred from string patterns.
17
+ - *Why*: The dot-prefix heuristic (`starts_with('.')`) classified `./my-project` as a target dir — a real bug caught by reviewers. Explicit arguments are boring but predictable, and predictable tools earn trust.
18
+
19
+ ## Managed Layout
20
+
21
+ ```text
22
+ project/
23
+ .agents/ # managed root (default)
24
+ mars.toml # desired sources + settings
25
+ mars.lock # generated lock/ownership/provenance
26
+ mars.local.toml # local overrides (gitignored)
27
+ .mars/ # internal state (sync.lock, cache)
28
+ agents/ # installed agent profiles
29
+ skills/ # installed skills
30
+ .claude/ # optional linked tool dir
31
+ agents -> ../.agents/agents
32
+ skills -> ../.agents/skills
33
+ ```
34
+
35
+ ## MarsContext Invariant
36
+
37
+ `src/cli/mod.rs` defines:
38
+
39
+ - `MarsContext { managed_root, project_root }`
40
+ - Invariant enforced by `MarsContext::new`: managed root must be a subdirectory and therefore has a parent.
41
+ - `project_root` is always `managed_root.parent()` (canonicalized when possible).
42
+
43
+ This invariant is relied on by local-path resolution and link-target resolution.
44
+
45
+ ## CLI Surface
46
+
47
+ ### Global flags
48
+
49
+ | Flag | Meaning |
50
+ |---|---|
51
+ | `--root <PATH>` | Use this managed root instead of auto-discovery. |
52
+ | `--json` | Machine-readable output. |
53
+
54
+ ### Commands
55
+
56
+ | Command | Purpose |
57
+ |---|---|
58
+ | `mars init [TARGET]` | Initialize managed root with `mars.toml` (optional `--link`). |
59
+ | `mars add <source>` | Add/update source, then sync. |
60
+ | `mars remove <source>` | Remove source, then prune managed items. |
61
+ | `mars sync` | Resolve + install to match config (`--force`, `--diff`, `--frozen`). |
62
+ | `mars upgrade [sources...]` | Maximize versions for all or selected sources. |
63
+ | `mars outdated` | Show available updates without applying changes. |
64
+ | `mars list` | List managed agents/skills (`--status` for checksum state). |
65
+ | `mars why <name>` | Explain source/provenance for an installed item. |
66
+ | `mars rename <from> <to>` | Add rename rule and sync to apply it. |
67
+ | `mars resolve [file]` | Mark conflicts resolved by updating installed checksums. |
68
+ | `mars override <source> --path <PATH>` | Set local dev override in `mars.local.toml`. |
69
+ | `mars link <target>` | Link managed `agents/` + `skills/` into tool dir (`--unlink`, `--force`). |
70
+ | `mars check [path]` | Validate a source package (structure/frontmatter/deps). |
71
+ | `mars doctor` | Validate config/lock/filesystem/link/dependency health. |
72
+ | `mars repair` | Force rebuild from config/sources (corrupt-lock recovery path). |
73
+
74
+ ### Exit codes
75
+
76
+ | Code | Meaning |
77
+ |---|---|
78
+ | `0` | Success (or clean report). |
79
+ | `1` | Action needed: unresolved conflicts (sync) or validation errors (check). |
80
+ | `2` | User/config/resolution/validation/link/frozen errors. |
81
+ | `3` | Source fetch, I/O, HTTP, or git command errors. |
82
+
83
+ ## Sync Pipeline
84
+
85
+ Sync is orchestrated in `src/sync/mod.rs` under `.mars/sync.lock`:
86
+
87
+ 1. Load config + local overrides; apply optional mutation.
88
+ 2. Resolve graph (versions, deps, source identities).
89
+ 3. Build target state.
90
+ 4. Compute diff.
91
+ 5. Create plan.
92
+ 6. Apply plan.
93
+ 7. Write new `mars.lock`.
94
+
95
+ Core apply chain: `target -> diff -> plan -> apply`.
96
+
97
+ ## Source Fetching
98
+
99
+ - GitHub HTTPS sources: archive download (`/archive/<sha>.tar.gz`) into global cache.
100
+ - SSH / non-GitHub HTTPS git sources: `git clone`/`git fetch` + checkout.
101
+ - Local path sources: canonicalized filesystem paths, read directly (no copy cache).
102
+
103
+ Global cache root: `~/.mars/cache` (override with `MARS_CACHE_DIR`).
104
+
105
+ ## Key Modules
106
+
107
+ | Module | Responsibility |
108
+ |---|---|
109
+ | `src/cli/` | Clap args, root discovery, command dispatch, output formatting. |
110
+ | `src/config/` | `mars.toml` + `mars.local.toml` schemas, load/save, merge to effective config. |
111
+ | `src/lock/` | `mars.lock` schema, load/write, lock rebuild from apply outcomes. |
112
+ | `src/sync/` | End-to-end sync orchestration + `target/diff/plan/apply`. |
113
+ | `src/resolve/` | Dependency + version resolution and graph ordering. |
114
+ | `src/source/` | Source parsing/fetching (git + path) and global cache handling. |
115
+ | `src/discover/` | Discover agents/skills by filesystem conventions. |
116
+ | `src/validate/` | Agent-to-skill dependency validation. |
117
+ | `src/merge/` | Three-way merge/conflict handling. |
118
+ | `src/fs/` | Atomic writes/installs and advisory file lock (`flock`). |
119
+ | `src/frontmatter/` | YAML frontmatter parsing for agent/skill metadata. |
120
+ | `src/manifest/` | Optional per-source `mars.toml` manifest loading. |
121
+ | `src/hash/` | SHA-256 hashing for files/directories. |
122
+ | `src/types.rs` | Typed identifiers/newtypes used across modules. |
123
+
124
+ ## Dev Workflow
125
+
126
+ ```bash
127
+ cargo build
128
+ cargo test
129
+ cargo clippy --all-targets -- -D warnings
130
+ cargo fmt --check
131
+ ```
132
+
133
+ Notes:
134
+
135
+ - Integration coverage is under `tests/` (CLI-level behavior).
136
+ - Prefer keeping changes localized to one module/command path when adding features.
137
+
138
+ ## Releasing
139
+
140
+ ```bash
141
+ ./scripts/release.sh patch --push # 0.0.1 → 0.0.2, push to trigger CI
142
+ ./scripts/release.sh minor --push # 0.0.2 → 0.1.0
143
+ ./scripts/release.sh 1.0.0 --push # explicit version
144
+ ./scripts/release.sh patch --dry # run checks only, don't tag
145
+ ```
146
+
147
+ The release script runs pre-release checks (fmt, clippy, tests, release build, version consistency between Cargo.toml and pyproject.toml), bumps both files, commits, tags, and optionally pushes. The `v*` tag triggers GitHub Actions to build platform wheels and publish to PyPI, npm, and crates.io.
148
+
149
+ Prerequisites for first release:
150
+ - Set up trusted publisher on PyPI (repo: `haowjy/mars-agents`, workflow: `release.yml`, environment: `pypi`)
151
+ - Create `pypi` environment in GitHub repo settings
152
+ - `NPM_TOKEN` and `CARGO_REGISTRY_TOKEN` secrets already configured
@@ -0,0 +1,152 @@
1
+ # Development Guide: mars-agents
2
+
3
+ Mars is an agent package manager for `.agents/` directories. It installs agent profiles and skills from git/local sources, tracks ownership in `mars.lock`, and links managed content into tool directories like `.claude/`.
4
+
5
+ ## Core Principles
6
+
7
+ 1. **Resolve first, then act.** Validate + build full desired state before mutating files. If any conflict or error is detected during resolution, zero mutations occur.
8
+ - *Why*: Partial failures leave users in states that are hard to diagnose. A user who sees "3 conflicts" can fix all three and retry. A user whose command half-completed has to figure out what happened first.
9
+
10
+ 2. **Atomic writes.** Config, lock, and installed files use temp + rename. Crash mid-write leaves the old file intact.
11
+ - *Why*: Mars manages files that agents and tools read continuously. A half-written mars.toml breaks every tool that reads it. tmp + rename is atomic on POSIX — no recovery logic needed.
12
+
13
+ 3. **Lock file is authority.** `mars.lock` defines managed ownership and checksums. If it's not in the lock, it's not managed.
14
+ - *Why*: Without a single authority, mars can't distinguish "user added this manually" from "mars installed this." The lock makes ownership explicit — safe coexistence with unmanaged files.
15
+
16
+ 4. **No heuristics.** User intent is expressed through explicit flags and arguments, not inferred from string patterns.
17
+ - *Why*: The dot-prefix heuristic (`starts_with('.')`) classified `./my-project` as a target dir — a real bug caught by reviewers. Explicit arguments are boring but predictable, and predictable tools earn trust.
18
+
19
+ ## Managed Layout
20
+
21
+ ```text
22
+ project/
23
+ .agents/ # managed root (default)
24
+ mars.toml # desired sources + settings
25
+ mars.lock # generated lock/ownership/provenance
26
+ mars.local.toml # local overrides (gitignored)
27
+ .mars/ # internal state (sync.lock, cache)
28
+ agents/ # installed agent profiles
29
+ skills/ # installed skills
30
+ .claude/ # optional linked tool dir
31
+ agents -> ../.agents/agents
32
+ skills -> ../.agents/skills
33
+ ```
34
+
35
+ ## MarsContext Invariant
36
+
37
+ `src/cli/mod.rs` defines:
38
+
39
+ - `MarsContext { managed_root, project_root }`
40
+ - Invariant enforced by `MarsContext::new`: managed root must be a subdirectory and therefore has a parent.
41
+ - `project_root` is always `managed_root.parent()` (canonicalized when possible).
42
+
43
+ This invariant is relied on by local-path resolution and link-target resolution.
44
+
45
+ ## CLI Surface
46
+
47
+ ### Global flags
48
+
49
+ | Flag | Meaning |
50
+ |---|---|
51
+ | `--root <PATH>` | Use this managed root instead of auto-discovery. |
52
+ | `--json` | Machine-readable output. |
53
+
54
+ ### Commands
55
+
56
+ | Command | Purpose |
57
+ |---|---|
58
+ | `mars init [TARGET]` | Initialize managed root with `mars.toml` (optional `--link`). |
59
+ | `mars add <source>` | Add/update source, then sync. |
60
+ | `mars remove <source>` | Remove source, then prune managed items. |
61
+ | `mars sync` | Resolve + install to match config (`--force`, `--diff`, `--frozen`). |
62
+ | `mars upgrade [sources...]` | Maximize versions for all or selected sources. |
63
+ | `mars outdated` | Show available updates without applying changes. |
64
+ | `mars list` | List managed agents/skills (`--status` for checksum state). |
65
+ | `mars why <name>` | Explain source/provenance for an installed item. |
66
+ | `mars rename <from> <to>` | Add rename rule and sync to apply it. |
67
+ | `mars resolve [file]` | Mark conflicts resolved by updating installed checksums. |
68
+ | `mars override <source> --path <PATH>` | Set local dev override in `mars.local.toml`. |
69
+ | `mars link <target>` | Link managed `agents/` + `skills/` into tool dir (`--unlink`, `--force`). |
70
+ | `mars check [path]` | Validate a source package (structure/frontmatter/deps). |
71
+ | `mars doctor` | Validate config/lock/filesystem/link/dependency health. |
72
+ | `mars repair` | Force rebuild from config/sources (corrupt-lock recovery path). |
73
+
74
+ ### Exit codes
75
+
76
+ | Code | Meaning |
77
+ |---|---|
78
+ | `0` | Success (or clean report). |
79
+ | `1` | Action needed: unresolved conflicts (sync) or validation errors (check). |
80
+ | `2` | User/config/resolution/validation/link/frozen errors. |
81
+ | `3` | Source fetch, I/O, HTTP, or git command errors. |
82
+
83
+ ## Sync Pipeline
84
+
85
+ Sync is orchestrated in `src/sync/mod.rs` under `.mars/sync.lock`:
86
+
87
+ 1. Load config + local overrides; apply optional mutation.
88
+ 2. Resolve graph (versions, deps, source identities).
89
+ 3. Build target state.
90
+ 4. Compute diff.
91
+ 5. Create plan.
92
+ 6. Apply plan.
93
+ 7. Write new `mars.lock`.
94
+
95
+ Core apply chain: `target -> diff -> plan -> apply`.
96
+
97
+ ## Source Fetching
98
+
99
+ - GitHub HTTPS sources: archive download (`/archive/<sha>.tar.gz`) into global cache.
100
+ - SSH / non-GitHub HTTPS git sources: `git clone`/`git fetch` + checkout.
101
+ - Local path sources: canonicalized filesystem paths, read directly (no copy cache).
102
+
103
+ Global cache root: `~/.mars/cache` (override with `MARS_CACHE_DIR`).
104
+
105
+ ## Key Modules
106
+
107
+ | Module | Responsibility |
108
+ |---|---|
109
+ | `src/cli/` | Clap args, root discovery, command dispatch, output formatting. |
110
+ | `src/config/` | `mars.toml` + `mars.local.toml` schemas, load/save, merge to effective config. |
111
+ | `src/lock/` | `mars.lock` schema, load/write, lock rebuild from apply outcomes. |
112
+ | `src/sync/` | End-to-end sync orchestration + `target/diff/plan/apply`. |
113
+ | `src/resolve/` | Dependency + version resolution and graph ordering. |
114
+ | `src/source/` | Source parsing/fetching (git + path) and global cache handling. |
115
+ | `src/discover/` | Discover agents/skills by filesystem conventions. |
116
+ | `src/validate/` | Agent-to-skill dependency validation. |
117
+ | `src/merge/` | Three-way merge/conflict handling. |
118
+ | `src/fs/` | Atomic writes/installs and advisory file lock (`flock`). |
119
+ | `src/frontmatter/` | YAML frontmatter parsing for agent/skill metadata. |
120
+ | `src/manifest/` | Optional per-source `mars.toml` manifest loading. |
121
+ | `src/hash/` | SHA-256 hashing for files/directories. |
122
+ | `src/types.rs` | Typed identifiers/newtypes used across modules. |
123
+
124
+ ## Dev Workflow
125
+
126
+ ```bash
127
+ cargo build
128
+ cargo test
129
+ cargo clippy --all-targets -- -D warnings
130
+ cargo fmt --check
131
+ ```
132
+
133
+ Notes:
134
+
135
+ - Integration coverage is under `tests/` (CLI-level behavior).
136
+ - Prefer keeping changes localized to one module/command path when adding features.
137
+
138
+ ## Releasing
139
+
140
+ ```bash
141
+ ./scripts/release.sh patch --push # 0.0.1 → 0.0.2, push to trigger CI
142
+ ./scripts/release.sh minor --push # 0.0.2 → 0.1.0
143
+ ./scripts/release.sh 1.0.0 --push # explicit version
144
+ ./scripts/release.sh patch --dry # run checks only, don't tag
145
+ ```
146
+
147
+ The release script runs pre-release checks (fmt, clippy, tests, release build, version consistency between Cargo.toml and pyproject.toml), bumps both files, commits, tags, and optionally pushes. The `v*` tag triggers GitHub Actions to build platform wheels and publish to PyPI, npm, and crates.io.
148
+
149
+ Prerequisites for first release:
150
+ - Set up trusted publisher on PyPI (repo: `haowjy/mars-agents`, workflow: `release.yml`, environment: `pypi`)
151
+ - Create `pypi` environment in GitHub repo settings
152
+ - `NPM_TOKEN` and `CARGO_REGISTRY_TOKEN` secrets already configured