commits
Retry-After fix (RFC 9110 Section 10.2.3):
- Implement actual HTTP-date parsing in retry_after_to_seconds using
Http_date.parse instead of returning None with a TODO comment
- Compute time difference from provided 'now' timestamp
- Return 0 for past dates (clamped to non-negative)
- Add 3 new tests for date-to-seconds conversion
HTTP/2 Connection Pooling Plan:
- Document the architectural conflict between Conpool (1 conn = 1 req)
and HTTP/2 multiplexing (1 conn = N streams)
- Propose H2_connection_pool module with proper stream slot management
- Define 5-phase implementation plan from low-risk fixes to optimizations
- Include data structures, API changes, and testing strategy
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add validate_h2_user_headers function to validate user-provided headers
for HTTP/2 compliance before pseudo-headers are added:
- Rejects pseudo-headers in user input (they should not provide them)
- Validates no uppercase in header names (RFC 9113 Section 8.2)
- Validates no connection-specific headers (RFC 9113 Section 8.2.2)
- Validates TE header only contains "trailers" if present
Call this validation in h2_adapter.ml for both request() and one_request()
functions to ensure HTTP/2 header constraints are enforced.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Same-origin check (RFC 6454):
- Include port in origin comparison, not just scheme and host
- http://example.com:80 and http://example.com:8080 are now different origins
Digest authentication (RFC 7616):
- Reject unknown algorithms instead of silent MD5 fallback
- Implement -sess algorithm variants (MD5-sess, SHA-256-sess)
with proper session key derivation: HA1 = hash(hash(u:r:p):nonce:cnonce)
HTTP methods (RFC 9110):
- Add request_body_semantics function with Body_required/Optional/Forbidden
- DELETE, OPTIONS, GET now correctly have Body_optional semantics
- Deprecate has_request_body in favor of the more accurate new function
Status codes:
- 501 Not Implemented and 505 HTTP Version Not Supported are no longer
marked as retryable (they indicate permanent conditions)
HTTP/2 (RFC 9113):
- Add SETTINGS_NO_RFC7540_PRIORITIES (0x09) to disable deprecated priorities
- Validate :protocol pseudo-header requires CONNECT method (RFC 8441)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
HTTP Message Signatures now use an explicit Eio clock for time validation
instead of Ptime_clock.now(), making the code testable and consistent with
Eio's capability-passing design.
Time validations now performed:
- Signatures with `expires` in the past are rejected
- Signatures with `created` in the future (beyond 60s clock skew) are rejected
- If `max_age` is specified and `created` is older, signature is rejected
API changes:
- sign/sign_with_digest now require ~clock parameter
- verify/verify_all now require ~clock parameter
- Auth.apply_signature now requires ~clock parameter
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
HTTP/2 Implementation:
- Add h2_frame module for RFC 7540 frame parsing/serialization
- Add h2_hpack module for RFC 7541 header compression (HPACK)
- Add h2_stream for HTTP/2 stream state machine
- Add h2_connection for multiplexed connection management
- Add h2_client high-level API matching HTTP/1.1 interface
- Add h2_adapter for protocol version abstraction
URI Library Migration:
- Replace custom Huri.t with Uri.t from uri opam package
- Keep Huri.write for efficient Buf_write serialization
- Remove Uri module shadowing from requests and apubt libraries
- Use Uri.* functions directly throughout codebase
Requests Library Reorganization:
- core/: fundamental types (body, headers, status, method, error)
- features/: optional functionality (auth, cache, retry, signature)
- h1/: HTTP/1.1 client implementation
- h2/: HTTP/2 client implementation
- parsing/: header and structured field parsers
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add Changelog module for Claude-based changelog generation
- Generate narrative prose (2-4 sentences) instead of bullet points
- Auto-detect channel members and use @**Name** Zulip mentions
- Focus on user-visible features and API changes
- Remove monopam dependency from poe library
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The loop command now responds to DMs and mentions while sleeping
between broadcast intervals, using Eio.Fiber.both to run both
loops concurrently.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds a new command (refresh/pull/sync/update) that can be triggered via
DM to the bot. The command:
1. Pulls latest changes from remote (git pull --ff-only)
2. Regenerates changelog (monopam changes --daily --aggregate)
3. Broadcasts new changes to the configured channel
This allows manual triggering of the same flow that runs in the polling
loop, useful for immediate updates without waiting for the next interval.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Consolidate the separate monopam_changes library into the main monopam
library as submodules (Changes.Aggregated, Changes.Daily, Changes.Query).
This simplifies the dependency graph and provides a cleaner interface.
Update poe to use the new Monopam.Changes interface and add:
- Git pull before checking for changes in the polling loop
- Detailed logging of git pull results (up-to-date vs new changes)
- --requests-verbose flag to control HTTP request logging (off by default)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Enables "develop in monorepo first, extract later" workflow by running
git subtree split to extract commits, creating a new repository in
checkouts, and configuring the remote URL. Optionally pushes to remote
and creates opam package metadata.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement OAuth 2.0 authentication for Mastodon instances alongside the
existing HTTP signature auth for ActivityPub federation.
New features:
- `apub auth login user@instance.social` - OAuth login with PKCE
- Commands (post, follow, like, boost) use Mastodon REST API when OAuth
credentials are available, falling back to ActivityPub federation
New files:
- apub_mastodon_oauth.ml - OAuth flow (app registration, PKCE, token exchange)
- apub_mastodon_api.ml - Mastodon REST API client (statuses, follows, etc.)
Session type changes:
- key_id and private_key_pem now optional (for OAuth-only sessions)
- New optional fields: oauth_instance, oauth_access_token, oauth_client_id,
oauth_client_secret
- Backwards compatible JSON codec
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
monopam:
- Make --aggregate the default for daily changes (add --no-aggregate to skip)
- Skip past days entirely if per-day file exists to avoid redundant Claude calls
- For today, still check if entry exists before regenerating
- Simplify Zulip format headers ("Updates for..." instead of "## Changes for...")
poe:
- Fix admin verification to use delivery_email from Zulip API
- Fallback to sender_email if API call fails
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change the daily changes system from single <repo>-daily.json files to
separate <repo>-<YYYY-MM-DD>.json files per day per repo, with hour
timestamps for real-time updates.
Key changes:
- Add hour and timestamp fields to daily_entry type for precise tracking
- Change file naming from <repo>-daily.json to <repo>-<date>.json
- Update load_daily/save_daily to work with per-day files
- Update generate_aggregated to find files by new pattern
- Add hour/timestamp to aggregated entry type for consistency
- Create new Daily module with immutable Map-based data structure
- Add query functions for real-time access (daily_changes_since, etc.)
The new Daily module provides:
- by_repo and by_date indexes using String_map
- Query functions: since, for_repo, for_date, repos, dates
- Loading functions: load_all, load_repo_day, load_repo_all
- Discovery functions: list_repos, list_dates
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
These executables are internal tests and examples that should not be
installed as public binaries.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit implements a comprehensive changes broadcast system:
**monopam_changes library** (new package):
- Aggregated module: Types and JSON codecs for daily changes format
- Query module: Functions to load changes since timestamp, format for Zulip
- Supports .changes/YYYYMMDD.json aggregated format
**monopam enhancements**:
- Added --aggregate flag to `monopam changes --daily` command
- Generates structured JSON files for broadcast system
- Added generate_aggregated function to Changes module
- Added rev_parse to Git module
**poe bot refactoring**:
- Commands module: Deterministic command parsing (help, status, broadcast, admin)
- Admin module: Storage management for broadcast state (last_time, git_head)
- Broadcast module: Smart broadcasting that only sends NEW changes
- Loop module: Hourly polling loop for automated change detection
- Config: Added admin_emails and changes_dir fields
- Handler: Updated to use command parser, delegate to modules
New poe commands:
- `poe loop --interval SECONDS` - Automated polling and broadcasting
- Admin commands: last-broadcast, reset-broadcast, storage keys/get/delete
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add authentication system for the apub CLI following the atp-auth pattern:
- New apub_auth library (lib/auth/) with session persistence
- Store actor credentials in ~/.config/apub/profiles/<profile>/session.json
- Support multiple profiles for different ActivityPub accounts
- Auto-load credentials for write commands (post, follow, like, boost)
CLI commands:
- apub auth setup <actor-uri> -k <key.pem> Import actor credentials
- apub auth status Show current profile
- apub auth logout Clear saved credentials
- apub auth profile list/switch/current Profile management
Write commands now work without explicit --actor/--key-file/--key-id
when credentials are saved via 'apub auth setup'.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Integrate ocaml-webfinger library for RFC 7033/7565 compliant discovery
- Add ActivityPub WebFinger spec to spec/ directory
- Add location and preview fields to Object type
- Add Question activity support (one_of, any_of, closed fields)
- Add CLI commands: post, follow, like, boost
- Fix Signing.from_pem to properly handle string PEM input
- Update PLAN.md marking all phases complete
- Update README.md with CLI documentation
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
42a9979 Expose accessor functions for Signing.key and user_agent
331449a Add project metadata for opam release
git-subtree-dir: ocaml-apubt
git-subtree-split: 42a9979e083a249b98c3b2520cdfb2ccbac52f18
a1fa899 Fix non-deterministic lexicon code generation
git-subtree-dir: ocaml-atp
git-subtree-split: a1fa8999f659c33660db64143f7d5fe813353c89
git-subtree-dir: ocaml-apubt
git-subtree-split: 06018cf01daa5ccff87441fa3084fe26b0bf649a
c074b19 Add Zulip standard [api] section config support and daily changelog
98a5561 Store poe config under unified XDG app name
git-subtree-dir: ocaml-zulip
git-subtree-split: c074b199446d2065bf0ce23b5ebe54e7d11f5245
git-subtree-dir: ocaml-webfinger
git-subtree-split: 9a2e6464c534862cf7b9152c78ff35c471506cbc
9f0d328 Store poe config under unified XDG app name
git-subtree-dir: poe
git-subtree-split: 9f0d328f3ca9e950481b279f3e2079577d60e9af
dda1358 Fix tangled.org URL parsing to strip @ prefix from username
4b3af82 monopam: Auto-create checkout on push if missing
git-subtree-dir: monopam
git-subtree-split: dda13588877f3199b31cc4dc2510df6b8bf6638d
ffeb22c Add accessors, pp functions, and missing .mli files to ocaml-matrix
c98278f Fix all odoc documentation warnings in ocaml-matrix
git-subtree-dir: ocaml-matrix
git-subtree-split: ffeb22c17c8d6a7aff093c689fee4422040e198e
8424c92 Refactor mail-flag to use polymorphic variants and move wire modules
cdedd0b Add unified mail-flag library for IMAP/JMAP interoperability
git-subtree-dir: ocaml-jmap
git-subtree-split: 8424c92aa2dac414ba48933129bd38f7ac346d1e
beffea3 Refactor mail-flag to use polymorphic variants and move wire modules
be23666 Add unified mail-flag library for IMAP/JMAP interoperability
cb5e7a0 Implement comprehensive IMAP RFC extensions
0713094 Add IMAP RFC specs and implementation plans
ea87a88 Add IMAP integration test suite and fix protocol bugs
git-subtree-dir: ocaml-imap
git-subtree-split: beffea327c75f5c5a45e0c39e024964442706506
9023a12 sync
849001f ocaml-atp: Regenerate lexicon bindings
git-subtree-dir: ocaml-atp
git-subtree-split: 9023a123f7f96aa2ba2ea37746af6841ef0e216a
The hermest code generator was producing different output on each run
due to multiple sources of non-determinism:
- group_nsids_by_prefix: trie children were in insertion order
- sort_children_by_deps: topological sort didn't order "ready" elements
- topo_sort_defs: same issue with definition sorting
- find_json_files: Sys.readdir returns files in unspecified order
All four are now fixed by sorting alphabetically where order was
previously undefined. Regenerated all lexicon files with the new
deterministic ordering.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements WebFinger protocol with jsont for JSON encoding/decoding,
requests library for HTTP, and cmdliner for CLI. Features abstract
Link and Jrd types, nullable property support, and comprehensive tests.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The tangled.org URL format uses @username in the path (e.g.,
https://tangled.org/@anil.recoil.org/foo). This strips the leading @
when converting to a push URL.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
git-subtree-dir: ocaml-mail-flag
git-subtree-split: ef50a8e84e8da9a232f397639a86cd183fda400b
Retry-After fix (RFC 9110 Section 10.2.3):
- Implement actual HTTP-date parsing in retry_after_to_seconds using
Http_date.parse instead of returning None with a TODO comment
- Compute time difference from provided 'now' timestamp
- Return 0 for past dates (clamped to non-negative)
- Add 3 new tests for date-to-seconds conversion
HTTP/2 Connection Pooling Plan:
- Document the architectural conflict between Conpool (1 conn = 1 req)
and HTTP/2 multiplexing (1 conn = N streams)
- Propose H2_connection_pool module with proper stream slot management
- Define 5-phase implementation plan from low-risk fixes to optimizations
- Include data structures, API changes, and testing strategy
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add validate_h2_user_headers function to validate user-provided headers
for HTTP/2 compliance before pseudo-headers are added:
- Rejects pseudo-headers in user input (they should not provide them)
- Validates no uppercase in header names (RFC 9113 Section 8.2)
- Validates no connection-specific headers (RFC 9113 Section 8.2.2)
- Validates TE header only contains "trailers" if present
Call this validation in h2_adapter.ml for both request() and one_request()
functions to ensure HTTP/2 header constraints are enforced.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Same-origin check (RFC 6454):
- Include port in origin comparison, not just scheme and host
- http://example.com:80 and http://example.com:8080 are now different origins
Digest authentication (RFC 7616):
- Reject unknown algorithms instead of silent MD5 fallback
- Implement -sess algorithm variants (MD5-sess, SHA-256-sess)
with proper session key derivation: HA1 = hash(hash(u:r:p):nonce:cnonce)
HTTP methods (RFC 9110):
- Add request_body_semantics function with Body_required/Optional/Forbidden
- DELETE, OPTIONS, GET now correctly have Body_optional semantics
- Deprecate has_request_body in favor of the more accurate new function
Status codes:
- 501 Not Implemented and 505 HTTP Version Not Supported are no longer
marked as retryable (they indicate permanent conditions)
HTTP/2 (RFC 9113):
- Add SETTINGS_NO_RFC7540_PRIORITIES (0x09) to disable deprecated priorities
- Validate :protocol pseudo-header requires CONNECT method (RFC 8441)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
HTTP Message Signatures now use an explicit Eio clock for time validation
instead of Ptime_clock.now(), making the code testable and consistent with
Eio's capability-passing design.
Time validations now performed:
- Signatures with `expires` in the past are rejected
- Signatures with `created` in the future (beyond 60s clock skew) are rejected
- If `max_age` is specified and `created` is older, signature is rejected
API changes:
- sign/sign_with_digest now require ~clock parameter
- verify/verify_all now require ~clock parameter
- Auth.apply_signature now requires ~clock parameter
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
HTTP/2 Implementation:
- Add h2_frame module for RFC 7540 frame parsing/serialization
- Add h2_hpack module for RFC 7541 header compression (HPACK)
- Add h2_stream for HTTP/2 stream state machine
- Add h2_connection for multiplexed connection management
- Add h2_client high-level API matching HTTP/1.1 interface
- Add h2_adapter for protocol version abstraction
URI Library Migration:
- Replace custom Huri.t with Uri.t from uri opam package
- Keep Huri.write for efficient Buf_write serialization
- Remove Uri module shadowing from requests and apubt libraries
- Use Uri.* functions directly throughout codebase
Requests Library Reorganization:
- core/: fundamental types (body, headers, status, method, error)
- features/: optional functionality (auth, cache, retry, signature)
- h1/: HTTP/1.1 client implementation
- h2/: HTTP/2 client implementation
- parsing/: header and structured field parsers
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add Changelog module for Claude-based changelog generation
- Generate narrative prose (2-4 sentences) instead of bullet points
- Auto-detect channel members and use @**Name** Zulip mentions
- Focus on user-visible features and API changes
- Remove monopam dependency from poe library
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds a new command (refresh/pull/sync/update) that can be triggered via
DM to the bot. The command:
1. Pulls latest changes from remote (git pull --ff-only)
2. Regenerates changelog (monopam changes --daily --aggregate)
3. Broadcasts new changes to the configured channel
This allows manual triggering of the same flow that runs in the polling
loop, useful for immediate updates without waiting for the next interval.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Consolidate the separate monopam_changes library into the main monopam
library as submodules (Changes.Aggregated, Changes.Daily, Changes.Query).
This simplifies the dependency graph and provides a cleaner interface.
Update poe to use the new Monopam.Changes interface and add:
- Git pull before checking for changes in the polling loop
- Detailed logging of git pull results (up-to-date vs new changes)
- --requests-verbose flag to control HTTP request logging (off by default)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement OAuth 2.0 authentication for Mastodon instances alongside the
existing HTTP signature auth for ActivityPub federation.
New features:
- `apub auth login user@instance.social` - OAuth login with PKCE
- Commands (post, follow, like, boost) use Mastodon REST API when OAuth
credentials are available, falling back to ActivityPub federation
New files:
- apub_mastodon_oauth.ml - OAuth flow (app registration, PKCE, token exchange)
- apub_mastodon_api.ml - Mastodon REST API client (statuses, follows, etc.)
Session type changes:
- key_id and private_key_pem now optional (for OAuth-only sessions)
- New optional fields: oauth_instance, oauth_access_token, oauth_client_id,
oauth_client_secret
- Backwards compatible JSON codec
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
monopam:
- Make --aggregate the default for daily changes (add --no-aggregate to skip)
- Skip past days entirely if per-day file exists to avoid redundant Claude calls
- For today, still check if entry exists before regenerating
- Simplify Zulip format headers ("Updates for..." instead of "## Changes for...")
poe:
- Fix admin verification to use delivery_email from Zulip API
- Fallback to sender_email if API call fails
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change the daily changes system from single <repo>-daily.json files to
separate <repo>-<YYYY-MM-DD>.json files per day per repo, with hour
timestamps for real-time updates.
Key changes:
- Add hour and timestamp fields to daily_entry type for precise tracking
- Change file naming from <repo>-daily.json to <repo>-<date>.json
- Update load_daily/save_daily to work with per-day files
- Update generate_aggregated to find files by new pattern
- Add hour/timestamp to aggregated entry type for consistency
- Create new Daily module with immutable Map-based data structure
- Add query functions for real-time access (daily_changes_since, etc.)
The new Daily module provides:
- by_repo and by_date indexes using String_map
- Query functions: since, for_repo, for_date, repos, dates
- Loading functions: load_all, load_repo_day, load_repo_all
- Discovery functions: list_repos, list_dates
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit implements a comprehensive changes broadcast system:
**monopam_changes library** (new package):
- Aggregated module: Types and JSON codecs for daily changes format
- Query module: Functions to load changes since timestamp, format for Zulip
- Supports .changes/YYYYMMDD.json aggregated format
**monopam enhancements**:
- Added --aggregate flag to `monopam changes --daily` command
- Generates structured JSON files for broadcast system
- Added generate_aggregated function to Changes module
- Added rev_parse to Git module
**poe bot refactoring**:
- Commands module: Deterministic command parsing (help, status, broadcast, admin)
- Admin module: Storage management for broadcast state (last_time, git_head)
- Broadcast module: Smart broadcasting that only sends NEW changes
- Loop module: Hourly polling loop for automated change detection
- Config: Added admin_emails and changes_dir fields
- Handler: Updated to use command parser, delegate to modules
New poe commands:
- `poe loop --interval SECONDS` - Automated polling and broadcasting
- Admin commands: last-broadcast, reset-broadcast, storage keys/get/delete
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add authentication system for the apub CLI following the atp-auth pattern:
- New apub_auth library (lib/auth/) with session persistence
- Store actor credentials in ~/.config/apub/profiles/<profile>/session.json
- Support multiple profiles for different ActivityPub accounts
- Auto-load credentials for write commands (post, follow, like, boost)
CLI commands:
- apub auth setup <actor-uri> -k <key.pem> Import actor credentials
- apub auth status Show current profile
- apub auth logout Clear saved credentials
- apub auth profile list/switch/current Profile management
Write commands now work without explicit --actor/--key-file/--key-id
when credentials are saved via 'apub auth setup'.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Integrate ocaml-webfinger library for RFC 7033/7565 compliant discovery
- Add ActivityPub WebFinger spec to spec/ directory
- Add location and preview fields to Object type
- Add Question activity support (one_of, any_of, closed fields)
- Add CLI commands: post, follow, like, boost
- Fix Signing.from_pem to properly handle string PEM input
- Update PLAN.md marking all phases complete
- Update README.md with CLI documentation
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
beffea3 Refactor mail-flag to use polymorphic variants and move wire modules
be23666 Add unified mail-flag library for IMAP/JMAP interoperability
cb5e7a0 Implement comprehensive IMAP RFC extensions
0713094 Add IMAP RFC specs and implementation plans
ea87a88 Add IMAP integration test suite and fix protocol bugs
git-subtree-dir: ocaml-imap
git-subtree-split: beffea327c75f5c5a45e0c39e024964442706506
The hermest code generator was producing different output on each run
due to multiple sources of non-determinism:
- group_nsids_by_prefix: trie children were in insertion order
- sort_children_by_deps: topological sort didn't order "ready" elements
- topo_sort_defs: same issue with definition sorting
- find_json_files: Sys.readdir returns files in unspecified order
All four are now fixed by sorting alphabetically where order was
previously undefined. Regenerated all lexicon files with the new
deterministic ordering.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>