Thanks for your interest in contributing. This document covers the conventions we use for issues, pull requests, and commits.
Before opening an issue, search the existing ones to make sure it hasn't been reported already.
We have two issue templates:
- Bug Report -- something is broken or behaving unexpectedly
- Feature Request -- a new capability or an improvement to an existing one
Pick the right template when you create an issue. Fill in every section -- incomplete reports take longer to triage.
- Steps to reproduce -- minimal, concrete steps. "It doesn't work" is not useful.
- Expected vs actual behavior -- what you thought would happen, and what happened instead.
- Environment -- Python version, OS, database type, which LLM provider you're using.
- Logs/screenshots -- paste the relevant traceback or attach a screenshot.
- Problem statement -- what pain point or limitation you're running into.
- Proposed solution -- how you think it should work. Doesn't need to be code-level; a clear description is enough.
- Alternatives considered -- anything else you thought about and why it's not ideal.
- Fork the repo and create a branch from
main. - Make your changes. Follow the code style described below.
- If you added functionality, add or update relevant tests/scripts in
experiment_scripts/. - Make sure the project imports cleanly:
uv run python -c "import xyz_agent_context.module; import xyz_agent_context.narrative; import xyz_agent_context.services; print('OK')" - Open a PR against
main.
- Title: short (under 72 chars), imperative mood. Same format as a commit message header.
- Good:
feat(job): add cron expression validation - Bad:
Updated some stuff in jobs
- Good:
- Description: explain what changed and why. Link to the related issue if there is one (
Closes #123). - Keep PRs focused. One logical change per PR. If you're fixing a bug and also refactoring nearby code, split them.
- No backward-compatibility hacks. We don't maintain deprecated code paths right now (see project principles). If something changes, it changes cleanly.
- At least one maintainer review is required before merge.
- CI checks must pass (import validation, lint if configured).
- Conversations should be resolved before merging.
We use Conventional Commits.
<type>(<scope>): <description>
[optional body]
[optional footer(s)]
| Type | When to use |
|---|---|
feat |
New feature or capability |
fix |
Bug fix |
refactor |
Code restructuring without behavior change |
docs |
Documentation only |
test |
Adding or updating tests |
perf |
Performance improvement |
chore |
Build, CI, dependency updates, housekeeping |
style |
Formatting, whitespace, semicolons (no logic change) |
Optional, but encouraged. Use the module or subsystem name:
feat(narrative): add topic-drift detection
fix(job): prevent duplicate cron triggers
refactor(module): extract instance lifecycle to separate method
docs(readme): add SQLite roadmap note
chore(deps): bump pydantic-settings to 2.5
- Subject line: imperative mood, lowercase, no period at the end, max 72 characters.
- Body: wrap at 72 characters. Explain what and why, not how.
- Breaking changes: add
!after type/scope and explain in the body or footer.feat(schema)!: rename agent_message.content to agent_message.body BREAKING CHANGE: all existing queries referencing the `content` column need to be updated to `body`. - One concern per commit. Don't mix a feature and a refactor in the same commit.
- Python 3.13+. Type hints where they add clarity (no need to annotate every local variable).
- All code comments and docstrings in English (CLAUDE.md ironclad rule #1: no Chinese in code). Docstrings follow the format in
CLAUDE.md. - No unnecessary abstractions. Three similar lines > a premature helper function.
- No backward-compatibility shims.
- Modules don't import from each other. Each module under
module/<name>_module/is self-contained. - Private packages stay private.
_module_impl/,_narrative_impl/,_event_impl/are internal. Import from the publicmodule/ornarrative/package instead. - Configuration goes through
settings.py. Noos.getenv()orload_dotenv()scattered around. Usefrom xyz_agent_context.settings import settings(lazy import in methods if needed to avoid circular deps). - Database access goes through
repository/. Table management scripts inutils/database_table_management/are standalone and should not be imported by application code. - Prompts stay generic. No scenario-specific examples (e.g., sales, customer support) hard-coded in prompts. Agents define their own scenarios via Awareness.
Every new Python file should have:
"""
@file_name: xxx.py
@author: Your Name
@date: 2025-xx-xx
@description: What this file does (one line)
Extended description if needed...
"""# Clone and install
git clone https://github.com/your-org/narra-nexus.git
cd narra-nexus
uv sync
# Copy and configure environment
cp .env.example .env
# Edit .env with your API keys and database config
# Create database tables
uv run python src/xyz_agent_context/utils/database_table_management/create_all_tables.py
# Run the backend (4 processes)
uv run python src/xyz_agent_context/module/module_runner.py mcp # MCP servers
uv run uvicorn backend.main:app --reload --port 8000 # API
uv run python -m xyz_agent_context.services.module_poller # Instance poller
uv run python -m xyz_agent_context.module.job_module.job_trigger --interval 60 # Job scheduler
# Run the frontend
cd frontend && npm install && npm run dev# Import check (catches circular imports, missing modules)
uv run python -c "import xyz_agent_context.module; import xyz_agent_context.narrative; import xyz_agent_context.services; print('OK')"
# Sync table schema if you modified any schema
cd src/xyz_agent_context/utils/database_table_management
uv run python sync_all_tables.py --dry-runSee README.md - Adding a New Module for the step-by-step guide.
Short version:
- Create
module/<name>_module/<name>_module.py, subclassXYZBaseModule. - Register in
module/__init__.py(MODULE_MAP). - Create table scripts in
utils/database_table_management/. - Create a repository in
repository/if needed. - Run the import check.
Open an issue with the question label, or start a Discussion if the repo has Discussions enabled.