194 lines
6.0 KiB
Markdown
194 lines
6.0 KiB
Markdown
# Contributing to The Nexus
|
|
|
|
## Issue Assignment — The Lock Protocol
|
|
|
|
**Rule: Assign before you code.**
|
|
|
|
Before starting work on any issue, you **must** assign it to yourself. If an issue is already assigned to someone else, **do not submit a competing PR**.
|
|
|
|
### For Humans
|
|
|
|
1. Check the issue is unassigned
|
|
2. Assign yourself via the Gitea UI (right sidebar → Assignees)
|
|
3. Start coding
|
|
|
|
### For Agents (Claude, Perplexity, Mimo, etc.)
|
|
|
|
1. Before generating code, call the Gitea API to check assignment:
|
|
```
|
|
GET /api/v1/repos/{owner}/{repo}/issues/{number}
|
|
→ Check assignees array
|
|
```
|
|
2. If unassigned, self-assign:
|
|
```
|
|
POST /api/v1/repos/{owner}/{repo}/issues/{number}/assignees
|
|
{"assignees": ["your-username"]}
|
|
```
|
|
3. If already assigned, **stop**. Post a comment offering to help instead.
|
|
|
|
### Why This Matters
|
|
|
|
On April 11, 2026, we found 12 stale PRs caused by Rockachopa and the `[claude]` auto-bot racing on the same issues. The auto-bot merged first, orphaning the manual PRs. Assignment-as-lock prevents this race condition.
|
|
|
|
---
|
|
|
|
## Branch Protection & Review Policy
|
|
|
|
All repositories enforce these rules on `main`:
|
|
|
|
| Rule | Status |
|
|
|------|--------|
|
|
| Require Pull Request for merge | ✅ Enabled |
|
|
| Require 1 approval before merge | ✅ Enabled |
|
|
| Dismiss stale approvals on new commits | ✅ Enabled |
|
|
| Require CI to pass (where CI exists) | ⚠️ Conditional |
|
|
| Block force pushes to `main` | ✅ Enabled |
|
|
| Block deletion of `main` branch | ✅ Enabled |
|
|
|
|
### Default Reviewer Assignments
|
|
|
|
| Repository | Required Reviewers |
|
|
|------------|-------------------|
|
|
| `hermes-agent` | `@perplexity`, `@Timmy` |
|
|
| `the-nexus` | `@perplexity` |
|
|
| `timmy-home` | `@perplexity` |
|
|
| `timmy-config` | `@perplexity` |
|
|
|
|
### CI Enforcement Status
|
|
|
|
| Repository | CI Status |
|
|
|------------|-----------|
|
|
| `hermes-agent` | ✅ Active |
|
|
| `the-nexus` | ⚠️ CI runner pending (#915) |
|
|
| `timmy-home` | ❌ No CI |
|
|
| `timmy-config` | ❌ Limited CI |
|
|
|
|
---
|
|
|
|
## Branch Naming
|
|
|
|
Use descriptive prefixes:
|
|
|
|
| Prefix | Use |
|
|
|--------|-----|
|
|
| `feat/` | New features |
|
|
| `fix/` | Bug fixes |
|
|
| `epic/` | Multi-issue epic branches |
|
|
| `docs/` | Documentation only |
|
|
|
|
Example: `feat/mnemosyne-memory-decay`
|
|
|
|
---
|
|
|
|
## PR Requirements
|
|
|
|
1. **Rebase before merge** — PRs must be up-to-date with `main`. If you have merge conflicts, rebase locally and force-push.
|
|
2. **Reference the issue** — Use `Closes #NNN` in the PR body so Gitea auto-closes the issue on merge.
|
|
3. **No bytecode** — Never commit `__pycache__/` or `.pyc` files. The `.gitignore` handles this, but double-check.
|
|
4. **One feature per PR** — Avoid omnibus PRs that bundle multiple unrelated features. They're harder to review and more likely to conflict.
|
|
|
|
---
|
|
|
|
## Path Conventions
|
|
|
|
| Module | Canon Path |
|
|
|--------|-----------|
|
|
| Mnemosyne (backend) | `nexus/mnemosyne/` |
|
|
| Mnemosyne (frontend) | `nexus/components/` |
|
|
| MemPalace | `nexus/mempalace/` |
|
|
| Scripts/tools | `bin/` |
|
|
| Git hooks/automation | `.githooks/` |
|
|
| Tests | `nexus/mnemosyne/tests/` |
|
|
|
|
**Never** create a duplicate module at the repo root (e.g., `mnemosyne/` when `nexus/mnemosyne/` already exists). Check `FEATURES.yaml` manifests for the canonical path.
|
|
|
|
---
|
|
|
|
## Feature Manifests
|
|
|
|
Each major module maintains a `FEATURES.yaml` manifest that declares:
|
|
- What exists (status: `shipped`)
|
|
- What's in progress (status: `in-progress`, with assignee)
|
|
- What's planned (status: `planned`)
|
|
|
|
**Check the manifest before creating new PRs.** If your feature is already shipped, you're duplicating work. If it's in-progress by someone else, coordinate.
|
|
|
|
Current manifests:
|
|
- [`nexus/mnemosyne/FEATURES.yaml`](nexus/mnemosyne/FEATURES.yaml)
|
|
|
|
---
|
|
|
|
## Workflow
|
|
|
|
1. Check the issue is unassigned → self-assign
|
|
2. Check `FEATURES.yaml` for the relevant module
|
|
3. Create feature branch from `main`
|
|
4. Submit PR with clear description and `Closes #NNN`
|
|
5. Wait for reviewer approval
|
|
6. Rebase if needed, then merge
|
|
|
|
### Emergency Exceptions
|
|
|
|
Hotfixes require:
|
|
- ✅ @Timmy approval
|
|
- ✅ Post-merge documentation
|
|
- ✅ Follow-up PR for full review
|
|
|
|
---
|
|
|
|
## Large-Repo Clone Strategy
|
|
|
|
Some repos in this org (hermes-agent, the-nexus as it grows) can exceed 1000 tracked files, which causes `git clone --depth 1` to time out and also hits the Gitea tree-API cap of 1000 entries.
|
|
|
|
### Recommended clone patterns for agents
|
|
|
|
**Blobless partial clone** — fastest overall; metadata arrives immediately, blobs are fetched on demand:
|
|
```sh
|
|
git clone --filter=blob:none --depth 1 <repo-url>
|
|
```
|
|
|
|
**Treeless partial clone** — skips tree objects for past commits; best when you need full working tree but not history:
|
|
```sh
|
|
git clone --filter=tree:0 <repo-url>
|
|
```
|
|
|
|
**Sparse checkout** — only materialise the subdirectories you actually need:
|
|
```sh
|
|
git clone --filter=blob:none --no-checkout <repo-url> myrepo
|
|
cd myrepo
|
|
git sparse-checkout init --cone
|
|
git sparse-checkout set nexus tests # only check out these dirs
|
|
git checkout main
|
|
```
|
|
|
|
### Gitea tree API workaround
|
|
|
|
When the tree endpoint returns exactly 1000 entries and you suspect truncation, pass `recursive=1` and page through with the `page` parameter:
|
|
```
|
|
GET /api/v1/repos/{owner}/{repo}/git/trees/{sha}?recursive=1&page=2
|
|
```
|
|
|
|
### Why `.gitattributes` export-ignore exists
|
|
|
|
Directories marked `export-ignore` in `.gitattributes` are excluded from `git archive` tarballs and future sparse-export tooling. This reduces the surface area for export-based agent workflows. It does **not** affect `git clone` directly — use the partial-clone flags above for that.
|
|
|
|
---
|
|
|
|
## Stale PR Policy
|
|
|
|
A cron job runs every 6 hours and auto-closes PRs that are:
|
|
1. **Conflicted** (not mergeable)
|
|
2. **Superseded** by a merged PR that closes the same issue or implements the same feature
|
|
|
|
Closed PRs receive a comment explaining which PR superseded them. If your PR was auto-closed but contains unique work, reopen it, rebase against `main`, and update the feature manifest.
|
|
|
|
---
|
|
|
|
## CI/CD Requirements
|
|
|
|
All main branch merges require (where applicable):
|
|
- ✅ Linting
|
|
- ✅ Unit tests
|
|
- ⚠️ Integration tests (pending for the-nexus, see #915)
|
|
- ✅ Security scans
|