Contributing¶
Thanks for your interest in improving NovelAI Image MCP! This page covers
the practical workflow. For the project’s code of conduct, see
CODE_OF_CONDUCT.md.
Before you start¶
Open an issue describing your proposed change. This is especially important for new features or API changes — we’ll discuss scope and design before you spend time on code.
Check the issue tracker for related work in progress.
Development setup¶
git clone https://github.com/xinvxueyuan/NovelAI-Image-MCP.git
cd NovelAI-Image-MCP
# Sync the workspace virtualenv (server + docs + dev tools)
uv sync
# (Optional) Install Node-side tooling for husky + markdownlint + turbo
corepack enable pnpm
pnpm install --frozen-lockfile
The first uv sync downloads all transitive dependencies; subsequent runs are instant.
Workflow¶
# 1. Branch off main
git checkout -b feat/my-feature
# 2. Implement your change.
# - Source under apps/server/src/
# - Tests under apps/server/tests/
# - Docs under apps/docs/source/ (if user-facing)
# 3. Run all checks locally before pushing.
uv run --directory apps/server poe check
# Equivalent to: ruff format-check + ruff check + pyright + pytest
# 4. (If you touched docs) verify the build:
uv run --package novelai-image-mcp-docs sphinx-build -b html apps/docs/source apps/docs/_build/html -W --keep-going
# 5. (If you touched markdown) verify markdownlint:
pnpm exec markdownlint-cli2
# 6. (If you touched licensing) verify REUSE compliance:
uv run reuse lint
# 7. Commit using Conventional Commits + gitmoji:
git commit -m "✨ feat: add support for V5 model ids"
# 8. Push and open a PR:
git push -u origin feat/my-feature
gh pr create --title "..." --body "..."
Pre-commit hook¶
If you’ve installed pnpm dependencies, a .husky/pre-commit hook runs
automatically on every git commit:
prek — ruff
--fix, ruff-format, and general hooks (trailing-whitespace, end-of-file-fixer, etc.).markdownlint — only when
.mdfiles are staged.pyright — only when
.pyfiles are staged.pytest — only when
.pyfiles are staged (slowest phase).
If prek modifies files, the hook re-stages them and retries once. If any phase fails, the commit aborts with a clear message.
To bypass for a WIP commit (use sparingly):
git commit --no-verify -m "wip: ..."
Warning
CI runs the same checks as the hook. A --no-verify commit will still
fail CI — bypass only for genuinely WIP work that you’ll rebase before
opening a PR.
Coding standards¶
Python¶
Style: enforced by
ruff(preview mode). Seeapps/server/pyproject.tomlfor the rule set. Runuv run --directory apps/server ruff formatto auto-format.Types: enforced by
pyright(standard mode). Type-check must pass.Docstrings: Google style (the project’s pydocstyle convention). Required on public APIs; optional on private helpers.
Imports:
from __future__ import annotationsis required at the top of every module (PEP 563 + RuffTCrules).Async: tools are async. Use
httpx.AsyncClientfor HTTP,pytest-asynciofor tests (asyncio_mode=auto).
Markdown¶
Use MyST Markdown (the docs site’s parser).
Line length is unlimited (
MD013disabled).Headings may not end with
.,;:!(MD026).Inline HTML is allowed (
MD033disabled) for callouts / details.Run
pnpm exec markdownlint-cli2 --fixto auto-fix most issues.
Licensing¶
All files must carry SPDX license headers.
REUSE.tomldeclares them by glob — usually you don’t need to add anything manually.Run
uv run reuse lintto verify compliance.Software code: MIT. Documentation: MIT. Visual elements + infrastructure: CC0-1.0.
Test coverage¶
Coverage floor: 70% (enforced by
--cov-fail-under=70).Tests live in
apps/server/tests/and usepytest-asyncio+respx(HTTP mocking).Every new public function should have at least one test.
Bugs should include a regression test.
See Testing for the test layout and fixture strategy.
Documentation¶
User-facing changes (new tool, new parameter, behavior change) must update the docs:
Tools →
apps/docs/source/tools/<tool>.mdTutorials →
apps/docs/source/tutorials/<tutorial>.mdConfiguration →
apps/docs/source/configuration.mdAPI → automatically generated by
sphinx.ext.autodocfrom docstrings
To preview docs locally:
uv run --package novelai-image-mcp-docs sphinx-autobuild apps/docs/source apps/docs/_build/html --open-browser
Contributing skills¶
Agent skills live under skills/<name>/SKILL.md and are registered in
skills.sh.json at the repository root. To add a new skill:
Run
npx skills init <name>to scaffold theSKILL.mdfrontmatter (name+descriptiononly, nometadatablock) and the## When to use→## Instructionsbody structure.Fill in the content — distribute guidance on demand, don’t duplicate what other skills already cover.
Add the skill to
skills.sh.jsonunder the appropriate grouping (CLI / MCP Tools / Workflows).Update the Agent skills docs page and the README skills table if the skill is user-facing.
See AGENTS.md → “Agent Skills (skills.sh)” for the full scaffold
conventions (frontmatter rules, H1 = skill name, description < 200 chars,
quoting rules for YAML special characters).
Translating docs¶
The docs site supports multiple languages via per-language source trees.
English lives at the apps/docs/source/ root; each additional language
lives under apps/docs/source/<lang-code>/ (e.g., source/zh/,
source/ja/). All languages share the same conf.py.
Rules¶
Full translations only — no stubs. A translated page must cover the full English source. Code blocks remain unchanged; only prose is translated. Do NOT create “translation in progress” placeholder pages — they break the build’s
-Wwarning gate and confuse users.Toctree scope = translated pages only. The
index.mdtoctree in each language directory must only reference pages that exist under that language’s directory. If a section (e.g.,tools/,tutorials/) is not translated, omit it from the translated toctree — users switch to English for untranslated sections.Preserve MyST directives. Keep all MyST syntax (
:::tip,=== "Unix"tabs,{toctree},{image}, etc.) intact. Only translate the prose inside them.CJK punctuation in headings.
MD026forbids trailing.,;:!in headings — use。、!?instead. (MD013line-length is disabled, so long CJK lines are fine.)
Adding a new language¶
Create
apps/docs/source/<code>/with at minimumindex.md.Add the language to
AVAILABLE_LANGUAGESinapps/docs/source/conf.py(tuple of(code, label, base_path)).Add the language to the matrix in
.github/workflows/docs.yml.Build locally and confirm zero warnings:
uv run --package novelai-image-mcp-docs sphinx-build -b html \ apps/docs/source/<code> apps/docs/_build/<code>/html \ -c apps/docs/source -D language=<code> -W --keep-going
Keeping translations in sync¶
When English source changes, update the translated page in the same PR if practical. Translated pages that fall badly out of sync should be deleted rather than left stale — a missing translation is better than a misleading one.
Commit messages¶
Follow Conventional Commits + gitmoji:
<emoji> <type>: <subject>
<body>
Type |
Use for |
|---|---|
|
New feature |
|
Bug fix |
|
Documentation only |
|
Formatting, whitespace, no code change |
|
Code restructure, no behavior change |
|
Performance improvement |
|
Adding / fixing tests |
|
Build system, dependencies, CI |
|
CI configuration changes |
|
Misc maintenance |
Common emojis:
Emoji |
Type |
|---|---|
✨ |
feat |
🐛 |
fix |
📝 |
docs |
🎨 |
style |
♻️ |
refactor |
⚡️ |
perf |
✅ |
test |
🏗️ |
build |
🔧 |
chore |
Pull request¶
One PR per logical change.
Title: Conventional Commit format (
feat:,fix:, etc.).Description: link the issue, summarize the change, list any breaking changes.
All CI checks must pass before merge.
Squash-and-merge into
main(the default branch).
Reporting bugs¶
Open a bug report issue. Include:
The exact command you ran.
The full error output (stack trace if Python).
The server version (via
uv run python -c "import novelai_image_mcp; print(novelai_image_mcp.__version__)").Your OS, Python version, and uv version.
A minimal reproduction (script or steps).
Reporting security issues¶
Do not open a public issue for security vulnerabilities. See
SECURITY.md
for the private disclosure process.