(AI generated. Not reviewed.)
Setup and Contributing
Table of Contents
- Local Development Commands
- Backend First
- OpenAPI Sync Discipline
- Verification Expectations
- CLI Harness And Importers
Local Development Commands
The commands below are the current repo-standard ones from AGENTS.md.
Backend
bash fichero-server/scripts/start_backend.sh
PYTHONPATH=fichero-server/src .venv/bin/ruff check fichero-server/src/
PYTHONPATH=fichero-server/src .venv/bin/pytest fichero-server/tests/unit/ --ignore=fichero-server/tests/unit/_archived
Swift
swiftlint lint fichero/fichero/
OpenAPI Sync
./fichero-server/scripts/sync_openapi_schema.sh
Backend First
The frontend depends on the engine being available. For the default macOS development path:
- open
fichero/fichero.xcodeproj - pick an Embedded scheme (e.g. “Fichero (Dev Embedded)”)
- build and run — the app spawns its own engine; nothing to start by hand
The Local schemes are for engine development: they connect to an engine you start
yourself with bash fichero-server/scripts/start_backend.sh on port 8765.
iOS/iPadOS do not start a local engine; they connect to an explicit remote host
configured through EngineConfig.
OpenAPI Sync Discipline
Any backend API change should trigger a contract check:
- Did the Pydantic model change?
- Did the route signature change?
- Does Swift need regenerated types?
- Do service wrappers need updating?
If the answer is yes, regenerate immediately. Do not leave the frontend and backend out of sync while continuing unrelated work.
Verification Expectations
This repo distinguishes between worker-level and integrator-level verification.
Worker-level expectations:
- lint the area you changed
- run focused tests for the touched backend area
- commit small, isolated increments
Manager or integrator expectations:
- build the Xcode project
- run the full
FicheroTestssuite - verify the cross-stack gate with the backend running
One more repo-specific rule matters for API work: if you change the backend API, you must commit the regenerated client-facing contract artifacts in the same change set so the Swift side stays buildable.
verify_all is tiered, not all-or-nothing
The shipped top-level verification entrypoint is scripts/verify_all.sh. It is
deliberately incremental on current main, not “always rerun everything”:
--fastruns Swift lint, backendruff, the cheapscripts/check_*.pyguardrails,scripts/check_version_date.sh, and the OpenAPI model-sync validator.--standardruns everything in--fast, then backend unit tests underfichero-server/tests/unit/.--fullruns--standardplus the requested platform legs. If you do not pass--macosor--ios,--fulldefaults to both.
The platform legs are separately requestable with --macos, --ios,
VERIFY_ALL_MACOS=1, or VERIFY_ALL_IOS=1, so callers can ask for an Xcode
leg without promoting the entire run to --full.
Verification artifacts and failure capture
verify_all.sh always writes build/verify_all_report.json, even on failure.
That report records the failing checks, the tier, the invoked command, and, for
the backend pytest leg, the parsed failing test node ids.
If the caller opts in with --file-issues, verify_all.sh shells into
scripts/verify_to_issues.sh --apply. That script de-duplicates by exact open
issue title, files follow-up GitHub issues into milestone-specific buckets, and
writes the manager handoff flag at build/verify_all_needs_fixing.json.
For cheap repo-level drift reporting, scripts/verify_report.py scans the
guardrail outputs directly and rolls them up into stable fingerprinted issues.
What runs when
Current repo intent in the shipped scripts and docs:
- workers use focused lint/tests for the area they touched
verify_all --fastis the cheap broad guardrail sweepverify_all --standardis the combined backend-quality gate- managers or integrators own the Xcode legs in
verify_all --full - nightly automation lives separately in
scripts/nightly-release.sh, which does the build health-check and publishes the daily prerelease artifact/notes
The cheap guardrail that keeps this contract from drifting is
scripts/check_verify_all_modes.py. It asserts that verify_all.sh still
exposes the documented fast/standard/full tiers, the opt-in platform flags, and
the linked smoke-checklist docs.
CLI Harness And Importers
Use the typed CLI as the first backend repro surface: CLI as Backend Test Harness.
Two practical rules matter now:
fichero auth loginstores a session token in~/Library/Application Support/Fichero/cli-session.json, and that session token is preferred over the bootstrap/shared-secret fallback.fichero import-manifestandfichero import-iiifneed a running engine; they are HTTP clients over the backend routes, not direct library writers.
Contributing Mechanics
New Swift files require registration
The Fichero main target uses traditional PBX file references. A .swift file written to disk is invisible to the Xcode compiler until it is registered:
ruby scripts/add-swift-file.rb fichero/fichero/Views/MyFolder/MyView.swift
scripts/add-swift-file.rb uses the xcodeproj Ruby gem (installed at ~/.gem/ruby/2.6.0/gems/xcodeproj-1.27.0/). Never edit project.pbxproj by hand. Test-target files are the exception; those use sync’d groups and are picked up automatically.
No per-task branches
Commit work directly to the milestone branch. Do not create a branch per issue
or per task. Isolated worktrees live under ~/code/fichero-worktrees/<name>,
not ad hoc sibling directories.
Conventional commits with issue references
feat: add document tagging endpoint (#420)
fix: resolve entity merge race condition (#388)
chore: bump ruff to 0.4.5
Prefixes: feat, fix, chore, refactor, test, docs, style. Always include the GitHub issue number when the commit closes or advances one.
Never push directly to main
All work goes through a PR. Create it and merge it yourself once the build gate passes.
0.0.x no-migration rule
Backend schema changes go into db.py _ensure_table via the Pydantic model field. Fresh databases pick up new columns automatically.
Do not add ALTER TABLE ADD COLUMN migration functions for columns that are already declared in the model when you are only targeting fresh databases. Persisted libraries still need idempotent ALTER and backfill work in db_migrations.py when a new column or structural change must land against real existing data.
Feature tier
bash fichero-server/scripts/start_backend.sh defaults to FICHERO_FEATURE_TIER=dev so local testing shows staged surfaces. Override with FICHERO_FEATURE_TIER=release when checking release-tier behavior. If your work is only active under FICHERO_FEATURE_TIER=dev, say so in your PR description. Core routes must work in release tier.
Expanding the Action Registry
Not every backend mutation goes through registry.invoke today. The action registry is the audited path for the domains that have been folded into it, especially the shared mutation path used by chat tools, App Intents, and undo/audit flows. Many route handlers still persist directly with db.save(...).
When you are extending an action-backed mutation surface, route handlers should look like this:
ctx = ActionContext(actor=request.state.user, origin_window=request.headers.get("X-Window-Id"))
result = registry.invoke(db, "document.tag", {"doc_id": doc_id, "tag": tag}, ctx)
return result
If you are adding a new shared, audited mutation, define it as a named action in the registry instead of inventing a parallel path. That gives it an audit record, change-event emission, and an undo hook where the action domain supports inversion.
See action-registry.md for the full guide: how to define an action, implement invert, write the required tests, and use the generic invocation endpoint.