-
-
Notifications
You must be signed in to change notification settings - Fork 0
chore: configure Papyrus development tools, skills, and agents #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| --- | ||
| name: papyrus-client | ||
| description: Implement or debug Papyrus Flutter UI, reader integration, local storage, and platform behavior in client/app. | ||
| --- | ||
|
|
||
| Read `client/AGENTS.md` from the Papyrus workspace. Work in `client/app`; use the | ||
| workspace's `tools/flutter`, `tools/dart`, and `tools/papyrus` for the pinned SDK. | ||
| Locate the workspace by ascending from the active directory to `.fvmrc` and `tools/papyrus`. | ||
|
|
||
| Trace a feature from its page/widget through the Provider state to its repository | ||
| or service. `lib/main.dart` owns composition; `lib/config/app_router.dart` owns | ||
| navigation. Inspect existing tests in the corresponding `test/` domain before | ||
| choosing a regression. For purely visual edits, inspect shared theme tokens and | ||
| responsive widgets rather than adding a second style system. | ||
|
|
||
| For persisted changes, follow writes and subscriptions in `lib/data` and | ||
| `lib/powersync`. A successful UI update is not evidence that an offline edit was | ||
| saved. Account for guest/user/server profile switches and scoped media caches. | ||
| For e-ink UI, inspect `lib/themes/app_motion.dart` and e-ink tests. For platform | ||
| changes, preserve conditional imports and validate the relevant target. | ||
|
|
||
| For reading changes, inspect `lib/reader` and the actual `papyrus_reader` revision | ||
| in `pubspec.yaml`/`pubspec.lock`. The sibling reader checkout is independent. EPUB | ||
| and PDF locators have different semantics; preserve restart/resume and progress. | ||
|
|
||
| Use Dart MCP with `client/app` as a root when available for diagnostics, tests and | ||
| running-app inspection. CLI checks remain available when MCP is not attached. | ||
| Consult Context7 or official docs for framework APIs specific to the installed SDK. | ||
|
|
||
| Run focused tests and `tools/papyrus check client`; for platform adapter changes, | ||
| also compile web or the affected available native target. Run the full suite when | ||
| the change spans shared composition/persistence. Distinguish analyzer warnings, | ||
| formatting debt, actual failures, and unrun targets. The OPDS network smoke test | ||
| needs `OPDS_SMOKE_URL`; it is not part of an ordinary offline test run. | ||
|
|
||
| If wire payloads, auth flows, or sync fields change, also read the workspace | ||
| `papyrus-sync-contract` skill. Do not broaden a client-only task into a backend | ||
| refactor unless the behavior requires it. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| interface: | ||
| display_name: "Papyrus Client" | ||
| short_description: "Flutter UI, persistence, and platform checks" | ||
| default_prompt: "Use $papyrus-client to implement and verify this Papyrus client change." |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| --- | ||
| name: papyrus-server | ||
| description: Implement or debug Papyrus FastAPI services, PostgreSQL persistence, auth, media, and Alembic migrations in server. | ||
| --- | ||
|
|
||
| Read `server/AGENTS.md` from the Papyrus workspace and work from `server/`. Locate | ||
| the workspace by ascending to `.fvmrc` and `tools/papyrus`. Use locked `uv` tools; | ||
| `tools/papyrus deps server` installs existing dev dependencies without upgrading. | ||
|
|
||
| Trace an endpoint from `papyrus/api/routes` through `papyrus/services` into schemas | ||
| and SQLAlchemy models. Keep domain rules and transaction orchestration in services. | ||
| New router modules need registration in `papyrus/api/routes/__init__.py`; new models | ||
| need exports through `papyrus.models` for Alembic discovery. | ||
|
|
||
| For ownership-sensitive changes, trace the authenticated user through every query, | ||
| referenced entity and media path. For sync changes, preserve atomic batches, | ||
| owner-level serialization, deletion tombstones and physical deletion after commit. | ||
| Inspect `papyrus/services/library_sync.py` and `sync.py` for the existing semantics. | ||
|
|
||
| For persisted schema changes, update models and add/review an Alembic revision. | ||
| Inspect both the existing database migration tests and affected domain tests. | ||
| Autogeneration needs a running database at the expected current revision; a generated | ||
| file alone does not verify an upgrade or data preservation. Apply migrations to a | ||
| disposable database when validation needs it. Honor existing approval requirements | ||
| for destructive production migrations. | ||
|
|
||
| Use `tools/papyrus test server -- tests/<focused_path>.py`. The test fixtures create | ||
| roles/databases and drop/recreate tables. They need local PostgreSQL even without an | ||
| `integration` marker. Do not run overlapping suites on the same test database. | ||
| CLI runs exclude externally backed `auth_smoke` tests; provider smoke testing is a | ||
| separate opt-in workflow. Do not print environment files or rotated auth tokens. | ||
|
|
||
| Run `tools/papyrus check server` for Ruff lint, non-mutating formatting and the | ||
| repo's configured strict Mypy. Mypy is installed and used by server CI; adding a | ||
| different type checker is not required. If sandbox TS changes, install with | ||
| `npm --prefix frontend/dev-pages ci`, then run its `typecheck` and `build` scripts. | ||
|
|
||
| For auth, upload or PowerSync wire changes, also read the workspace | ||
| `papyrus-sync-contract` skill and inspect the corresponding client tests. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| interface: | ||
| display_name: "Papyrus Server" | ||
| short_description: "FastAPI services, migrations, and database tests" | ||
| default_prompt: "Use $papyrus-server to implement and verify this Papyrus backend change." |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| --- | ||
| name: papyrus-sync-contract | ||
| description: Coordinate or review Papyrus client/server changes to auth, PowerSync schemas, offline uploads, ownership, and media contracts. | ||
| --- | ||
|
|
||
| Use for changes that cross the client/server boundary. Find the Papyrus workspace | ||
| by ascending to `.fvmrc` and `tools/papyrus`; read the affected component AGENTS.md. | ||
| Read [contract map](references/contract-map.md) for exact code and test locations. | ||
| Check only the contract involved in the request. | ||
|
|
||
| For a synced field, follow the full round trip: Dart model and mapper -> SQLite | ||
| column -> queued CRUD serialization -> server Pydantic validation -> owned SQLAlchemy | ||
| row -> PowerSync SELECT/alias -> client decoding and repository subscription. | ||
| Check ID aliases, omitted versus null fields, booleans, UTC timestamps, JSON text, | ||
| foreign-key ownership and local-only guest behavior. Update all required layers | ||
| together; a route test alone cannot prove the replicated field round trip. | ||
|
|
||
| Preserve upload transaction acknowledgment after successful server persistence. | ||
| Failed batches must remain retryable. Server batches serialize per owner and commit | ||
| atomically; deleting physical media occurs after commit. Tombstones stop delayed | ||
| offline writes from reviving deleted entities. Tests should prove the affected | ||
| failure mode, including account/server profile isolation when relevant. | ||
|
|
||
| For auth, trace refresh, token expiry, logout and profile transition as well as the | ||
| successful sign-in. Distinguish opaque refresh tokens, short-lived API access JWTs | ||
| and PowerSync credentials. Keep browser callbacks/deep links and API prefixes | ||
| compatible with the client's configured server URI. | ||
|
|
||
| Choose focused client and server regressions from the reference map. Run the relevant | ||
| component checks. A live sync test needs the API, PowerSync, publication/replication, | ||
| keys and a supported native test target; skipped live tests must be reported as | ||
| unrun. Do not modify user libraries or purge local state to make a test pass. | ||
|
|
||
| For coordinated implementation, settle payload/schema decisions before assigning | ||
| disjoint client/server edits. If delegation is requested, use client/server roles | ||
| and the contract reviewer. Serialize database tests on each shared test database. | ||
| Report the contract change, tests on both sides, migration needs and unverified | ||
| round-trip behavior. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| interface: | ||
| display_name: "Papyrus Sync Contract" | ||
| short_description: "Auth and offline sync across client and server" | ||
| default_prompt: "Use $papyrus-sync-contract to trace and verify this Papyrus contract change." |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| # Contract entry points | ||
|
|
||
| Paths below are relative to the Papyrus workspace. Verify the current source before | ||
| changing a contract; this map identifies owners rather than freezing field lists. | ||
|
|
||
| | Contract | Client | Server | | ||
| | --- | --- | --- | | ||
| | API base/prefix | `client/app/lib/auth/papyrus_api_config.dart` | `server/papyrus/config.py`, `server/papyrus/main.py` | | ||
| | Auth/token lifecycle | `client/app/lib/auth/{auth_api_client,auth_repository,token_store}.dart`, `lib/providers/auth_provider.dart` | `server/papyrus/api/routes/auth.py`, `schemas/auth.py`, `services/auth/` | | ||
| | PowerSync credentials and upload queue | `client/app/lib/powersync/papyrus_powersync_connector.dart` | `server/papyrus/api/routes/sync.py`, `schemas/sync.py`, `services/sync.py` | | ||
| | Library schema and row mapping | `client/app/lib/powersync/{papyrus_schema,powersync_book_mapper,library_row_mapper,library_database}.dart` | `server/papyrus/models/sync.py`, `schemas/book.py`, `services/library_validation.py`, `services/library_sync.py` | | ||
| | Replication projection | `client/app/lib/powersync/papyrus_schema.dart` | `server/powersync/sync-config.yaml`, `scripts/setup_local_powersync.sh` | | ||
| | Profiles and repository watches | `client/app/lib/powersync/{powersync_service,sync_profile_switch_queue}.dart`, `lib/data/data_store.dart` | JWT user identity and row ownership predicates | | ||
| | Media upload/cache | `client/app/lib/media/`, `lib/services/book_download_service*` | `server/papyrus/api/routes/media.py`, `services/media.py`, `schemas/media.py` | | ||
| | OPDS relay | `client/app/lib/opds/opds_http_client.dart` | `server/papyrus/api/routes/opds.py`, `services/opds.py`, `schemas/opds.py`, `docs/opds-relay.md` | | ||
| | Managed acquisition | `client/app/lib/acquisition/`, `lib/providers/acquisition_downloads_provider.dart` | `server/papyrus/api/routes/acquisition.py`, `services/acquisition.py`, `services/acquisition_monitor.py` | | ||
|
|
||
| ## Useful existing regressions | ||
|
|
||
| - Client sync: `client/app/test/powersync/`, especially mapper, persistence, connector, | ||
| live-library, schema-mode and profile-switch tests. | ||
| - Client auth: `client/app/test/auth/`, `test/providers/auth_provider_test.dart`. | ||
| - Client media isolation: `client/app/test/media/media_profile_switch_contract_test.dart`, | ||
| `media_storage_scope_test.dart`, and upload queue tests. | ||
| - Server batches/ownership/deletion: `server/tests/api/routes/test_sync.py`, | ||
| `test_library_sync.py`, `test_bookmark_sync.py`, `tests/services/test_sync.py`. | ||
| - Server schema/projection: `server/tests/test_powersync_sync_config.py`, | ||
| `test_library_migration.py`, `test_bookmark_migration.py`. | ||
| - Server auth: `server/tests/api/routes/test_auth.py`, `tests/services/test_auth.py`. | ||
| - End-to-end: `client/app/integration_test/powersync_books_integration_test.dart` | ||
| is gated by `RUN_POWERSYNC_INTEGRATION=true`. It registers temporary users and | ||
| validates two clients, offline reconnect, deletion and isolation against live | ||
| services. It imports `dart:io`; do not describe it as a browser integration test. | ||
|
|
||
| Example focused checks, from the workspace: | ||
|
|
||
| ```bash | ||
| tools/papyrus test client -- test/powersync/papyrus_powersync_connector_test.dart | ||
| tools/papyrus test server -- tests/api/routes/test_sync.py tests/services/test_sync.py | ||
| ``` | ||
|
|
||
| For a deliberately requested live run on an available native device: | ||
|
|
||
| ```bash | ||
| tools/papyrus test client -- integration_test/powersync_books_integration_test.dart \ | ||
| -d macos --dart-define=RUN_POWERSYNC_INTEGRATION=true \ | ||
| --dart-define-from-file=.dart_defines | ||
| ``` | ||
|
|
||
| Check `tools/flutter devices` first. Configure server auth/email requirements for | ||
| the disposable test users before running. Never equate the test's default skip | ||
| with a successful live sync run. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| name = "papyrus_client" | ||
| description = "Flutter client implementation and focused widget, persistence, and platform tests." | ||
| developer_instructions = """ | ||
| Work in the assigned client files. Read client/AGENTS.md and use the papyrus-client | ||
| skill when relevant. Trace UI state through providers into repositories. Preserve | ||
| offline writes, profile isolation, theme tokens, responsive layouts and e-ink motion. | ||
| Use the pinned SDK and run focused analysis/tests. Editing reader/ does not change | ||
| the Git-pinned client dependency. Share HTTP or sync contract changes with the parent. | ||
| Report changed files, verification, and remaining uncertainty. Do not change another | ||
| agent's files or update submodule revisions without the parent assigning that work. | ||
| """ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| name = "papyrus_contract_reviewer" | ||
| description = "Read-only review of client/server auth, offline sync, ownership, and reader compatibility." | ||
| sandbox_mode = "read-only" | ||
| developer_instructions = """ | ||
| Review the assigned diff and trace affected callers across the client/server boundary. | ||
| Use the papyrus-sync-contract skill. Check wire names, IDs, null clearing, serialized | ||
| JSON, booleans/timestamps, profile isolation, auth refresh, queue acknowledgement, | ||
| ownership, atomicity and tombstones where relevant. For reader changes check the | ||
| client's actual pinned dependency. Prioritize concrete regressions with file/line | ||
| evidence and a reproduction or missing regression test. Do not edit files, install | ||
| packages, start services or run database tests. Separate confirmed bugs from unknowns. | ||
| Return concise actionable findings and any material verification gaps. | ||
| """ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| name = "papyrus_server" | ||
| description = "FastAPI services, schemas, async persistence, migrations, and focused backend tests." | ||
| developer_instructions = """ | ||
| Work in the assigned server files. Read server/AGENTS.md and use the papyrus-server | ||
| skill when relevant. Keep routes thin and business rules in async services. Preserve | ||
| ownership checks, atomic sync batches, tombstones and post-commit media cleanup. | ||
| Include reviewed migrations when persisted schemas change. Use locked uv tools and | ||
| coordinate database tests with the parent; fixtures recreate tables and cannot share | ||
| a database concurrently. Run relevant tests, Ruff and Mypy. Share contract changes | ||
| with the parent. Report changed files, verification, and remaining uncertainty. | ||
| """ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| [agents] | ||
| max_concurrent_threads_per_session = 2 | ||
|
Comment on lines
+1
to
+2
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Even after correcting the concurrency key, Codex custom roles must be declared as AGENTS.md reference: AGENTS.md:L56-L58 Useful? React with 👍 / 👎. |
||
|
|
||
| [mcp_servers.dart] | ||
| command = "bash" | ||
| args = ["-c", 'while [ ! -x tools/dart-mcp ]; do if [ "$PWD" = / ]; then echo "Papyrus workspace not found" >&2; exit 1; fi; cd ..; done; exec ./tools/dart-mcp'] | ||
| startup_timeout_sec = 120 | ||
| tool_timeout_sec = 120 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| { | ||
| "flutter": "3.41.2", | ||
| "runPubGetOnSdkChanges": false, | ||
| "updateVscodeSettings": false, | ||
| "updateGitIgnore": false | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| name: Workspace tooling | ||
|
|
||
| on: | ||
| push: | ||
| paths: | ||
| - 'tools/**' | ||
| - '.vscode/setup.sh' | ||
| - '.github/workflows/tooling.yml' | ||
| pull_request: | ||
| paths: | ||
| - 'tools/**' | ||
| - '.vscode/setup.sh' | ||
| - '.github/workflows/tooling.yml' | ||
| workflow_dispatch: | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| jobs: | ||
| tooling: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - uses: actions/setup-python@v5 | ||
| with: | ||
| python-version: '3.12' | ||
| - name: Install ShellCheck | ||
| run: | | ||
| sudo apt-get update | ||
| sudo apt-get install -y shellcheck | ||
| - name: Check workspace commands | ||
| run: tools/papyrus check tooling | ||
| - name: Check setup script | ||
| run: shellcheck .vscode/setup.sh |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,4 @@ | ||
| .DS_Store | ||
| .fvm/ | ||
| .local/ | ||
| __pycache__/ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| { | ||
| "recommendations": [ | ||
| "Dart-Code.flutter", | ||
| "Dart-Code.dart-code", | ||
| "ms-python.python", | ||
| "charliermarsh.ruff", | ||
| "openai.chatgpt" | ||
| ] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| { | ||
| "dart.flutterSdkPath": ".fvm/flutter_sdk", | ||
| "dart.projectSearchDepth": 6, | ||
| "python.defaultInterpreterPath": "${workspaceFolder}/server/.venv/bin/python", | ||
| "python.analysis.extraPaths": ["${workspaceFolder}/server"], | ||
| "ruff.path": ["${workspaceFolder}/server/.venv/bin/ruff"], | ||
| "git.detectSubmodules": true, | ||
| "git.autoRepositoryDetection": "subFolders", | ||
| "[dart]": { | ||
| "editor.defaultFormatter": "Dart-Code.dart-code", | ||
| "editor.formatOnSave": true | ||
| }, | ||
| "[python]": { | ||
| "editor.defaultFormatter": "charliermarsh.ruff", | ||
| "editor.formatOnSave": true | ||
| }, | ||
| "files.watcherExclude": { | ||
| "**/.fvm/**": true, | ||
| "**/.local/**": true, | ||
| "**/.venv/**": true, | ||
| "**/.dart_tool/**": true, | ||
| "**/build/**": true | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When Codex loads this trusted-project configuration, it fails before starting a session or MCP server: validating
agents.max_concurrent_threads_per_session=2withcodex exec --strict-configreportsinvalid type: integer '2', expected struct AgentRoleToml in agents, whereasagents.max_threads=2is accepted. Rename this setting tomax_threads; otherwise Codex is unusable in the repository rather than merely failing to enforce the intended two-agent limit.Useful? React with 👍 / 👎.