Settings: Add full header with name/description/links (docs, getting started, bugs, GitHub). Add CSS for collapsible section spacing/borders. Default useSameModelForAll to false (show all three tiers). Governance: SECURITY.md, CONTRIBUTING.md, CHANGELOG.md, CircleCI config, PR template, issue templates (bug report, feature request). Deps: Update esbuild to 0.28.0, vitest to 4.1.4 (fixes both Dependabot alerts, 0 vulnerabilities).
7.0 KiB
Contributing to PENNY
Thank you for your interest in contributing to PENNY. This guide covers everything you need to get started.
Table of Contents
- Development Setup
- Architecture Overview
- Branch Model
- Making Changes
- Code Style
- Testing
- Commit Messages
- Pull Request Process
- Branch Protection Setup (Maintainers)
Development Setup
Prerequisites
- Node.js 20 or later
- npm
- An Obsidian vault for manual testing
- Git
Getting Started
# Fork the repository on GitHub, then:
git clone https://github.com/<your-username>/obsidian-penny.git
cd obsidian-penny
npm install
# Start the development build (watches for changes):
npm run dev
# Run the test suite:
npm test
# Run a production build:
npm run build
Testing in Obsidian
- Build the plugin (
npm run devfor watch mode, ornpm run buildfor a one-off build). - Copy or symlink
main.js,manifest.json, andstyles.cssinto your vault's.obsidian/plugins/penny/directory. - Reload Obsidian (Ctrl/Cmd + R) and enable PENNY in Settings > Community Plugins.
Architecture Overview
PENNY separates pure logic from the Obsidian runtime shell:
src/
core/ Pure-logic modules (no Obsidian imports)
annotations/ Annotation parsing, classification, scope detection
versioning/ Chapter version management, idempotency
routing/ Complexity scoring, model tier assignment
voice/ Voice compliance checking
providers/ LLM provider abstraction (Anthropic, Ollama)
config/ Configuration loading, PENNY.md parsing
git/ Git operations (commit message generation, staging)
shell/ Obsidian-specific code
plugin.ts Main plugin class, command registration
settings.ts Settings tab UI
commands/ Command implementations that bridge core <-> Obsidian
Key principle: Modules under src/core/ must never import from obsidian. They receive all Obsidian-specific data (file contents, paths, settings) through function parameters. This keeps the core testable without mocking Obsidian APIs.
Provider abstraction: All LLM calls go through a provider interface. Adding a new provider means implementing the interface and registering it -- no changes to annotation processing or routing logic.
Branch Model
main-- Release branch. Protected. Only receives merges fromdevelopvia pull request. Every merge tomainis a release.develop-- Integration branch. This is the default branch. All feature and fix branches merge here first.- Feature branches -- Branch from
develop, namedfeature/<short-description>orfix/<short-description>.
main -------- release tags
\
develop -- integration
\
feature/my-feature
Making Changes
- Fork the repository.
- Create a branch from
develop:git checkout develop git pull origin develop git checkout -b feature/my-feature - Make your changes.
- Write or update tests.
- Ensure all tests pass:
npm test - Ensure the build succeeds:
npm run build - Commit using conventional commit format (see below).
- Push to your fork and open a pull request against
develop.
Code Style
- TypeScript strict mode. The
tsconfig.jsonenforces strict checks. Do not weaken them. - No
any. Use proper types. If you need a flexible type, useunknownand narrow it. - Pure functions where possible. Functions in
src/core/should take inputs and return outputs without side effects. Side effects belong insrc/shell/. - No Obsidian imports in
src/core/. This is a hard boundary. If you need Obsidian functionality in a core module, pass it as a parameter or callback. - Explicit return types on exported functions.
- No default exports. Use named exports.
Testing
# Run all tests
npm test
# Run tests in watch mode (re-runs on file changes)
npm run test:watch
# Run tests with coverage report
npm run test:coverage
Testing Requirements
- All existing tests must pass before submitting a PR.
- New features must include tests.
- Bug fixes should include a regression test.
- Tests live in
test/and mirror thesrc/directory structure. - Tests for
src/core/modules should not require mocking Obsidian APIs (that is the whole point of the architecture split).
Commit Messages
Use Conventional Commits:
<type>(<scope>): <short description>
<optional body>
<optional footer>
Types
| Type | When to use |
|---|---|
feat |
New feature |
fix |
Bug fix |
docs |
Documentation only |
style |
Formatting, no logic change |
refactor |
Code restructuring, no feature or fix |
test |
Adding or updating tests |
chore |
Build, CI, tooling, dependency updates |
Examples
feat(annotations): add RESEARCH annotation type
fix(versioning): handle chapters with no existing versions
docs: update annotation guide with RESEARCH examples
test(routing): add coverage for edge-case complexity scores
chore(ci): add CircleCI type-check step
Pull Request Process
- Open your PR against
develop(notmain). - Fill out the PR template completely.
- Ensure CI passes (type check, tests, build).
- Request review from a maintainer.
- Address review feedback. Push new commits (do not force-push during review).
- Once approved, a maintainer will merge.
PR Checklist
- Branch is based on
develop - All tests pass (
npm test) - Build succeeds (
npm run build) - No
anytypes introduced - No Obsidian imports in
src/core/ - New features have tests
- Documentation updated if needed
- Commit messages follow conventional format
Branch Protection Setup (Maintainers)
The following commands configure branch protection and the default branch. These require admin access to the repository and should be run once during initial setup:
# Protect the main branch: require status checks, enforce on admins, require 1 approving review
gh api repos/KofTwentyTwo/obsidian-penny/branches/main/protection \
-X PUT \
-f required_status_checks='{"strict":true,"contexts":["test"]}' \
-f enforce_admins=true \
-f required_pull_request_reviews='{"required_approving_review_count":1}' \
-f restrictions=null
# Set develop as the default branch
gh api repos/KofTwentyTwo/obsidian-penny -X PATCH -f default_branch=develop
Questions?
Open a discussion or reach out via an issue. We are happy to help you get oriented.