padosoft / laravel-patent-box-tracker
Laravel package that classifies R&D activity across one or more git repositories with a deterministic LLM-based classifier and emits an audit-grade PDF + JSON dossier suitable for the Italian Patent Box (110% R&D super-deduction) regime.
Package info
github.com/padosoft/laravel-patent-box-tracker
pkg:composer/padosoft/laravel-patent-box-tracker
Requires
- php: ^8.3
- illuminate/console: ^12.0|^13.0
- illuminate/database: ^12.0|^13.0
- illuminate/http: ^12.0|^13.0
- illuminate/support: ^12.0|^13.0
- laravel/ai: ^0.6
- symfony/yaml: ^7.0|^8.0
Requires (Dev)
- dompdf/dompdf: ^3.0
- laravel/pint: ^1.18
- orchestra/testbench: ^10.0|^11.0
- phpstan/phpstan: ^2.0
- phpunit/phpunit: ^11.0|^12.0
- spatie/browsershot: ^5.0.5
Suggests
- dompdf/dompdf: Pure-PHP PDF dossier renderer fallback for environments without headless Chromium (CI runners, air-gapped servers).
- padosoft/laravel-ai-regolo: Lets the classifier run on Italian sovereign Regolo infrastructure for cost + GDPR reasons. Any laravel/ai SDK provider works.
- spatie/browsershot: Highest-fidelity PDF dossier renderer (Chromium-backed). Pair with DomPDF for environments without headless Chromium.
- dev-main
- v1.0.1
- v1.0.0
- v0.1.3
- v0.1.2
- v0.1.1
- v0.1.0
- dev-task/api-dossier-detail-endpoint
- dev-task/release-readme-tag-final
- dev-task/api-contract-tests-docs
- dev-task/release-readme-tag
- dev-task/api-contract-tests-docs-subtask-5.4-release-docs
- dev-task/api-security-hardening
- dev-task/api-read-models-subtask-2.4-show-dossier
- dev-task/api-read-models
- dev-task/api-foundation-hardening
- dev-task/api-write-jobs
This package is auto-updated.
Last update: 2026-05-08 10:09:54 UTC
README
Audit-grade Italian Patent Box dossier generator for Laravel.
Walks one or more git repositories, classifies every commit with a deterministic LLM pipeline, correlates the activity with design-doc evidence and AI-attribution markers, and emits a tamper-evident PDF + JSON dossier suitable for the Italian Patent Box (110% R&D super-deduction) regime β the artefact the taxpayer attaches to "documentazione idonea" filings with Agenzia delle Entrate.
v1.0.0 β production-ready. CLI + fluent API + stable HTTP API v1 + companion web admin panel + AI vibe-coding pack in the box.
Table of contents
- Why this package
- What ships in v1.0
- Companion admin web panel
- Design rationale
- Features at a glance
- Comparison vs alternatives
- Italian Patent Box primer
- Installation
- Quick start
- Usage examples
- HTTP API v1 (stable)
- Configuration reference
- Architecture
- π AI vibe-coding pack included
- Testing
- Roadmap
- Contributing
- Security
- License & credits
Why this package
The Italian Patent Box (regime "Nuovo Patent Box" introduced from FY2021 and consolidated under D.L. 146/2021 art. 6) grants a 110% super-deduction on qualified R&D costs incurred to develop intangible assets β patents, registered software (SIAE), industrial designs. Each β¬1 of qualified R&D effectively saves around β¬0.30 of tax (IRPEF + IRAP + INPS combined for an Italian sole proprietor).
The mandatory counterpart is documentation. To survive an Agenzia delle Entrate audit, the taxpayer must produce on demand:
- Identification of the qualified IP β patent number, SIAE registration ID, design certificate.
- Time-bound trail of R&D activity β what was done, when, by whom, on which IP.
- Phase classification of each activity β research, design, implementation, validation, documentation.
- Cost allocation β hourly rates Γ hours Γ phase, mapped to fiscal-year buckets.
- Tamper-evident integrity β the documentation must demonstrate it could not have been retroactively fabricated.
The current state of practice for software IP is manually compiled spreadsheets reconstructed from memory, calendars, and Git logs. This is expensive (a commercialista bills 8β20 hours per dossier) and error-prone (commits drift in classification, AI-assisted code is rarely separated, cross-repo work is hand-stitched).
laravel-patent-box-tracker replaces the manual reconstruction with a deterministic pipeline that walks the repositories and produces the same artefact in minutes β with hash-chain tamper evidence, deterministic-seeded LLM classification, and a hand-graded golden-set release gate.
Dogfooding angle
The package was built by an Italian Patent Box filer for Italian Patent Box filers. Padosoft (ditta individuale) uses it to file the FY2026 dossier on the AskMyDocs IP and the Padosoft Apache-2.0 sister packages. Every release is validated against a real feature/v4.x history with commercialista review before tagging.
Community angle
No equivalent package exists on Packagist. The closest analogues β gitinspector, commitlint + custom downstream tooling, Toggl / Harvest plugins, commercialista Excel templates β solve adjacent problems but none produce the documentation that Agenzia delle Entrate actually accepts for the documentazione idonea regime. The market gap is real and large enough that the package is expected to drive its own adoption arc.
What ships in v1.0
v1.0.0 is the first stable release. Public API is locked under SemVer; HTTP API is
/api/patent-box/v1/...and frozen.
- β
Deterministic classification pipeline β
temperature=0+ fixed seed + recorded prompt/model β byte-identical re-runs. - β
Four pluggable evidence collectors β
GitSourceCollector,AiAttributionExtractor,DesignDocCollector,BranchSemanticsCollectorwith boot-time FQCN validation and non-overlappingsupports()predicates (R23). - β
Hand-graded golden-set release gate β β₯ 80% F1 on real
feature/v4.xcommits, validated by commercialista review before everyv*.*.0tag. - β Italian fiscal A4 PDF + machine-readable JSON sidecar β Browsershot (Chromium) primary, DomPDF fallback. Ready for documentazione idonea filings.
- β Per-commit hash chain + per-dossier SHA-256 β retroactive edits to either the repo or the dossier break the chain at the exact tampered row.
- β
Cross-repository orchestration β single YAML config, per-repo roles (
primary_ip,support,meta_self), one consolidated dossier in minutes. - β
Cost-cap pre-flight guard β projects token cost before any LLM call; aborts with exit code 2 over
cost_cap_eur_per_run(default β¬50). - β
Three Artisan commands + fluent PHP builder β
patent-box:track,patent-box:render,patent-box:cross-repo, plusPatentBoxTracker::for(...). - β
Stable HTTP API v1 β opt-in, versioned, unified
{data, meta?, error}envelope, fixed error taxonomy, optional token gate, configurable rate limiter, contract-fixture tests in CI. Full surface in HTTP API v1 (stable). - β
Companion admin web panel β see
padosoft/laravel-patent-box-tracker-adminfor a production-grade Laravel admin UI on top of the v1 API. - β
AI vibe-coding pack β
.claude/directory with skills, rules, agents and slash-commands shipping in every release β see π AI vibe-coding pack included. - β
Opt-in live test suite β point
PATENT_BOX_LIVE_API_KEYat a real provider key to verify classifier accuracy and PDF rendering against real APIs. Default suite remains 100% offline. - β CI matrix β every push runs against PHP 8.3 / 8.4 / 8.5 Γ Laravel 12 / 13 plus a dedicated API-contract job.
Companion admin web panel
padosoft/laravel-patent-box-tracker-adminships the production-grade Laravel admin UI on top of this package.
Admin panel dashboard β FY-bound KPIs (sessions, classified commits, R&D-qualified, projected vs actual cost, dossiers), phase distribution, AI attribution split, hash-chain integrity badge, recent sessions table. Source: padosoft/laravel-patent-box-tracker-admin.
This package is API-first and CLI-first. If you want a polished web interface for non-technical users (commercialista, auditor, project lead) to drive sessions, browse classifications, fix labels, and download dossiers β install the companion admin panel:
π¦ padosoft/laravel-patent-box-tracker-admin
The admin panel is a separate package on purpose:
- Zero coupling β
laravel-patent-box-trackerhas no dependency on the admin. You can run it headless (CLI/API only) for years without ever installing the panel. - Talks the public v1 API β the admin is just a typed client + UI on top of
/api/patent-box/v1/.... Anything the panel does, you can do via cURL/Postman. - Drop-in install β
composer require padosoft/laravel-patent-box-tracker-adminmounts the panel under a configurable prefix; auth is host-app-driven (Sanctum, session, custom guard). - Designed for fiscal review β session detail view, classification audit trail, cost projection, PDF preview, integrity check button, evidence link inspection.
Pick what you need: tracker only, tracker + admin, or admin in a separate operations app pointing at a centralized tracker β they all work.
Design rationale
A few decisions are worth surfacing up front, because they shape the package's footprint and the kind of bugs you can or cannot have.
1. Deterministic-seeded classifier, not "AI magic"
Every LLM call goes out with temperature=0, top_p=1, and a fixed seed. Re-running on the same commit produces an identical classification. The dossier metadata records the prompt, the model, and the seed, so a Patent Box auditor can re-execute the run and verify byte-for-byte. This is non-negotiable for an audit-grade artefact: a stochastic classifier is not "documentation" β it is "guesswork that happens to be written down".
2. Hand-graded golden set as a release gate
Before tagging v0.1.0, a 50-commit manually-labelled validation set is held to β₯ 80% F1. The golden set is drawn from real feature/v4.x history with the labels assigned by Lorenzo + a commercialista review. Synthetic accuracy claims ("the model says it works") do not pass the gate; only labels a fiscal reviewer signed off on do.
3. Provider-agnostic via laravel/ai
The classifier depends on the SDK abstraction, not on a specific provider. The default uses Regolo (Italian sovereign cloud, EUR-billed, GDPR-friendly), but anyone can swap to OpenAI, Anthropic, Gemini, or any other laravel/ai provider in one config line. The package itself ships zero provider credentials β they live in the consumer's .env.
4. Hash-chain tamper evidence
Every tracked commit gets H(prev_hash || commit_sha) recorded in the dossier. The full chain is published in the appendix of the PDF and as a manifest in the JSON sidecar. Any retroactive edit to the underlying repo is detectable; any retroactive edit to the dossier itself breaks the chain at the exact tampered row.
5. Standalone agnostic β no AskMyDocs glue
The package has zero dependencies on lopadova/askmydocs (CE), padosoft/askmydocs-pro, or any other Padosoft proprietary code. It works in any Laravel 12/13 application that has laravel/ai installed. The reverse direction is the only one that exists: AskMyDocs uses this package, never the inverse. An architecture test enforces the boundary on every CI run.
6. API-first, admin separate
The HTTP API is the contract. The web admin panel is a separate package that consumes that contract. Headless installs never install the admin; admin installs never bypass the API. One contract, two delivery surfaces.
Features at a glance
- Audit-grade dossier β Italian fiscal A4 portrait PDF + machine-readable JSON sidecar, suitable for the documentazione idonea regime under D.M. 6 ottobre 2022 + provv. AdE 15 febbraio 2023.
- Deterministic LLM classifier β
temperature=0, fixedseed, recorded prompt and model version in the dossier metadata. Re-runs are byte-identical. - Hash-chain tamper evidence β per-commit
H(prev_hash || commit_sha)plus a SHA-256 of the entire JSON sidecar. Retroactive edits to either the repo or the dossier break the chain at the tampered row. - Four pluggable evidence collectors β
GitSourceCollector,AiAttributionExtractor,DesignDocCollector,BranchSemanticsCollector. Boot-time FQCN validation + non-overlappingsupports()predicates. - Cross-repository orchestration β single YAML config drives the dossier across N repos with per-repo roles (
primary_ip,support,meta_self). - AI attribution detection β parses
Co-Authored-Bytrailers (Claude, Copilot, custom) and committer-email signatures intohuman/ai_assisted/ai_authored/mixedper commit. - Design-doc correlation β auto-links commits to PLAN / ADR / spec / lessons-learned files by filename match, slug match, and date proximity.
- Branch-semantics heuristics β
feature/v4.0-W*-...β development phase,chore/*β typically non-qualified,fix/*β context-dependent (pre-release qualifies, post-release maintenance does not). - Cost-cap hard stop β pre-flight token-cost projection; aborts with exit code 2 before exceeding
cost_cap_eur_per_run(default β¬50). No accidental classification of a 10-year-old monorepo at full price. - Three Artisan commands + fluent builder β
patent-box:track,patent-box:render,patent-box:cross-repo. PlusPatentBoxTracker::for(...)for programmatic use. - Hand-graded golden set β₯ 80% F1 β release gate enforced before every
v*.*.0tag. Realfeature/v4.xcommits, real commercialista-validated labels. - Browsershot PDF + DomPDF fallback β Chromium fidelity by default, DomPDF for environments where headless Chromium is unavailable.
- Stable HTTP API v1 β opt-in, versioned, envelope-standardized, queue-aware, integrity-aware. See HTTP API v1 (stable).
- Companion admin web panel β separate package
padosoft/laravel-patent-box-tracker-admin. - Standalone agnostic β zero dependency on
lopadova/askmydocsorpadosoft/askmydocs-pro. Works on any Laravel project. Composable with sister Padosoft packages. - Strict typing β PHP 8.3+, readonly DTOs, fully-typed signatures, Pint-formatted, PHPStan analysis on every PR.
- CI matrix β every push runs against PHP 8.3 / 8.4 / 8.5 Γ Laravel 12 / 13 (6 cells) + dedicated API contract job.
- π AI vibe-coding pack ships in the box β every release includes the Padosoft Claude pack under
.claude/(skills, rules, agents, slash-commands). The moment youcomposer requirethis package and open the project in Claude Code, the agent picks up Padosoft's house conventions automatically. - π§ͺ Opt-in live test suite β point
PATENT_BOX_LIVE_API_KEYat a real provider key and runvendor/bin/phpunit --testsuite Liveto verify classifier accuracy and PDF rendering against real APIs. Default suite remains 100% offline.
Comparison vs alternatives
If you are evaluating how to assemble an Italian Patent Box dossier today, here are the realistic options on the table.
| Capability | gitinspector + scripts |
Toggl / Harvest plugins | Commercialista Excel templates | DIY git-log + spreadsheet | laravel-patent-box-tracker |
|---|---|---|---|---|---|
| Walks git history per repo | β | β | β | β | β |
| Cross-repository orchestration | β οΈ DIY | β | β | β οΈ DIY | β |
| Phase classification (research/design/impl/etc.) | β | β οΈ manual | β οΈ manual | β οΈ manual | β |
AI-attribution detection (Co-Authored-By) |
β | β | β | β οΈ DIY | β |
| Design-doc evidence linking (PLAN / ADR / spec) | β | β | β | β οΈ DIY | β |
| Deterministic / reproducible runs | β | β | β | β | β |
| Hash-chain tamper evidence | β | β | β | β | β |
| Italian fiscal A4 PDF template | β | β | β οΈ partial | β | β |
| Machine-readable JSON sidecar (gestionale-friendly) | β | β | β | β | β |
| Cost-cap pre-flight guard | N/A | N/A | N/A | N/A | β |
| Hand-graded accuracy gate (β₯ 80% F1) | N/A | N/A | N/A | N/A | β |
| Stable HTTP API for admin/automations | β | β | β | β | β |
| Production admin web panel available | β | β | β | β | β |
| Reproducible by Agenzia delle Entrate auditor | β οΈ partial | β | β | β οΈ partial | β |
| Time to assemble FY dossier | days | days | ~10β20 h | days | minutes |
Bottom line: generic git-stat tools and time-trackers solve a different problem; commercialista Excel templates are the manual baseline this package replaces; DIY scripts duplicate the work each fiscal year. laravel-patent-box-tracker is the only option that produces the exact artefact the documentazione idonea regime expects, with the tamper-evidence and reproducibility a fiscal review demands.
Italian Patent Box primer
Skip this section if you already file Italian Patent Box dossiers.
The Patent Box is a tax incentive available to entrepreneurs (artigiani included), companies (SRL, SpA), and professionals (with VAT registration) that develop qualified intangible IP and incur R&D costs to do so.
| Element | Detail |
|---|---|
| Qualified IP | Software protected by copyright (typically registered with SIAE), patents (UIBM or EPO), industrial designs, certain trademarks before 2022. |
| Qualified R&D costs | Personnel, AI tooling subscriptions, cloud compute, contractor invoices, dedicated equipment, IP registration fees. Marketing, sales, generic admin do NOT qualify. |
| Phase taxonomy | Research, experimental development, design, implementation, integration, validation, documentation. Manutenzione (post-release bug fixes) does NOT qualify; pre-release fixes generally do. |
| Documentation regime | "Documentazione idonea" (D.M. 6 ottobre 2022 + provv. AdE 15 febbraio 2023) protects against monetary penalties on classification errors if the dossier is filed. Option communicated in the tax return. |
| Cost calculation | Qualified costs Γ 110% = additional deduction. The base 100% is already deducted normally; the +10% is the incentive. |
| Audit window | Agenzia delle Entrate can challenge the dossier within 5 fiscal years from filing. |
This package targets the documentazione idonea regime: the output dossier is what the taxpayer attaches when communicating the option, and what they hand to Agenzia delle Entrate during audit.
Installation
composer require laravel/ai composer require padosoft/laravel-patent-box-tracker
The package auto-registers via Laravel's package discovery β no manual provider entry in config/app.php needed.
Publish the config:
php artisan vendor:publish --tag=patent-box-tracker-config
Run the migrations to create the storage tables (tracking_sessions, tracked_commits, tracked_evidence, tracked_dossiers):
php artisan migrate
Configure your laravel/ai provider of choice (Regolo is the default; OpenAI, Anthropic, Gemini all work). Minimal .env:
# Pick any laravel/ai provider β Regolo recommended for cost (~β¬0.05 per 1k commits). REGOLO_API_KEY=rg_live_... PATENT_BOX_DRIVER=regolo PATENT_BOX_MODEL=claude-sonnet-4-6
Want the web admin panel?
composer require padosoft/laravel-patent-box-tracker-admin
See the companion admin package for full setup and panel routes.
Quick start
Single-repository dossier
php artisan patent-box:track /path/to/your/repo \
--from=2026-01-01 --to=2026-12-31 \
--provider=regolo --model=claude-sonnet-4-6
The command walks the repo, classifies every commit, persists a tracking_session, and prints the session id. Render the dossier:
php artisan patent-box:render <session-id> --format=pdf --out=storage/dossier-2026.pdf php artisan patent-box:render <session-id> --format=json --out=storage/dossier-2026.json
Cross-repository dossier (the canonical Padosoft use case)
Save your fiscal config under version control:
# config/patent-box-2026.yml fiscal_year: 2026 period: from: 2026-01-01 to: 2026-12-31 tax_identity: denomination: Padosoft di Lorenzo Padovani p_iva: IT01234567890 regime: documentazione_idonea cost_model: hourly_rate_eur: 80 daily_hours_max: 8 classifier: provider: regolo model: claude-sonnet-4-6 repositories: - path: /home/lpad/Code/askmydocs role: primary_ip - path: /home/lpad/Code/laravel-ai-regolo role: support - path: /home/lpad/Code/laravel-flow role: support - path: /home/lpad/Code/eval-harness role: support - path: /home/lpad/Code/laravel-pii-redactor role: support - path: /home/lpad/Code/laravel-patent-box-tracker role: meta_self manual_supplement: off_keyboard_research_hours: 60 conferences: - { name: "Laracon EU 2026", days: 3 } ip_outputs: - kind: software_siae title: "AskMyDocs Enterprise Platform v4.0" registration_id: "SIAE-2026-..." - kind: brevetto_uibm title: "Canonical Knowledge Compilation Engine" application_id: "PCT/IT2026/..."
Then run:
php artisan patent-box:cross-repo config/patent-box-2026.yml
You get one consolidated dossier across N repositories, with cross-repo summaries and per-repo subtotals β in minutes.
Usage examples
Fluent builder API
use Padosoft\PatentBoxTracker\PatentBoxTracker; $session = PatentBoxTracker::for([ '/path/to/askmydocs', '/path/to/laravel-ai-regolo', '/path/to/laravel-flow', ]) ->coveringPeriod('2026-01-01', '2026-12-31') ->classifiedBy('regolo') ->withTaxIdentity([ 'denomination' => 'Padosoft di Lorenzo Padovani', 'p_iva' => 'IT01234567890', 'fiscal_year' => '2026', 'regime' => 'documentazione_idonea', ]) ->withCostModel([ 'hourly_rate_eur' => 80, 'daily_hours_max' => 8, ]) ->run(); // $session is a TrackingSession Eloquent model with relations to TrackedCommit / TrackedEvidence.
Render the dossier
$dossier = $session->renderDossier() ->locale('it') ->toPdf(); $dossier->save(storage_path('dossier-2026.pdf')); // JSON sidecar (machine-readable, hash-chain signed). $session->renderDossier()->toJson()->save(storage_path('dossier-2026.json'));
Inspect classification results
use Padosoft\PatentBoxTracker\Models\TrackedCommit; $qualified = TrackedCommit::query() ->where('tracking_session_id', $session->id) ->where('is_rd_qualified', true) ->orderByDesc('rd_qualification_confidence') ->get(); foreach ($qualified as $commit) { echo "{$commit->sha} [{$commit->phase}] {$commit->ai_attribution} β {$commit->rationale}\n"; }
Verify hash chain integrity
use Padosoft\PatentBoxTracker\Hash\HashChainBuilder; $verified = HashChainBuilder::verify($session); if (! $verified->isValid()) { throw new RuntimeException( "Tamper detected at commit {$verified->brokenAt} β chain breaks at this row." ); }
Extending the pipeline with a custom collector
use Padosoft\PatentBoxTracker\Sources\EvidenceCollector; final class CalendarCollector implements EvidenceCollector { public function supports(string $kind): bool { return $kind === 'calendar'; } public function collect(array $context): array { // Walk Google Calendar / Outlook events, return Evidence DTOs. return []; } } // Register in a service provider: $this->app->tag([CalendarCollector::class], 'patent-box.collectors');
The registry validates at boot that every tagged FQCN actually implements EvidenceCollector, and that no two collectors' supports() predicates overlap (R23).
HTTP API v1 (stable)
The package is CLI-first and fluent-API-first by default. The HTTP API is opt-in (off by default) and stable since v1.0.
Enable it in config:
// config/patent-box-tracker.php 'api' => [ 'enabled' => true, 'prefix' => 'api/patent-box', 'middleware' => ['api'], // or ['api', 'auth:sanctum'] etc. 'rate_limiter' => '60,1', // 60 hits per minute per IP/user 'auth_token' => env('PATENT_BOX_API_TOKEN'), // optional bearer/header gate ],
Surface
| Method | Path | Purpose |
|---|---|---|
| GET | /api/patent-box/v1/health |
Readiness probe |
| GET | /api/patent-box/v1/capabilities |
Frontend bootstrap (locales, regimes, providers, limits) |
| POST | /api/patent-box/v1/repositories/validate |
Validate a repo path before any LLM cost |
| POST | /api/patent-box/v1/tracking-sessions/dry-run |
Cost projection / pre-flight |
| POST | /api/patent-box/v1/tracking-sessions |
Queue a new tracking session |
| GET | /api/patent-box/v1/tracking-sessions |
List with filters/pagination |
| GET | /api/patent-box/v1/tracking-sessions/{id} |
Detail |
| GET | /api/patent-box/v1/tracking-sessions/{id}/commits |
Commits with advanced filters (ai_attribution, rd_confidence_min/max, search) |
| GET | /api/patent-box/v1/tracking-sessions/{id}/evidence |
Evidence with path_like / search |
| GET | /api/patent-box/v1/tracking-sessions/{id}/dossiers |
Dossier list with format/locale filters and meta |
| GET | /api/patent-box/v1/tracking-sessions/{id}/dossiers/{dossier} |
Dossier detail |
| GET | /api/patent-box/v1/tracking-sessions/{id}/dossiers/{dossier}/download |
Session-scoped, path-traversal-safe download |
| POST | /api/patent-box/v1/tracking-sessions/{id}/dossiers |
Queue dossier render |
| GET | /api/patent-box/v1/tracking-sessions/{id}/integrity |
Hash-chain verification |
Response envelope
Every response uses the same envelope:
{
"data": { "...": "..." },
"meta": { "page": 1, "per_page": 20, "total": 134 },
"error": null
}
Errors use a fixed taxonomy: validation_failed, not_found, conflict, cost_cap_exceeded, unauthorized, rate_limited, internal_error.
Full reference: docs/API_REFERENCE.md.
Configuration reference
The full default config lives at config/patent-box-tracker.php. Key entries:
| Key | Type | Default | Notes |
|---|---|---|---|
patent-box-tracker.classifier.driver |
string | regolo |
Any laravel/ai provider key (openai, anthropic, gemini, regolo, ...). |
patent-box-tracker.classifier.model |
string | env('PATENT_BOX_MODEL', 'claude-sonnet-4-6') |
Default classifier model. Heavier models trade cost for F1. |
patent-box-tracker.classifier.temperature |
float | 0 |
Do not change unless you understand the audit-trail implications. |
patent-box-tracker.classifier.seed |
int | 0xC0DEC0DE |
Fixed seed for byte-identical re-runs. |
patent-box-tracker.classifier.batch_size |
int | 20 |
Commits per LLM call. Higher = cheaper, lower = more diff context per commit. |
patent-box-tracker.classifier.cost_cap_eur_per_run |
float | 50.00 |
Hard stop. Run aborts with exit code 2 before exceeding this projected cost. |
patent-box-tracker.regime |
string | documentazione_idonea |
Italian Patent Box regime. documentazione_idonea enables the penalty-protection contract under D.M. 6 ottobre 2022; non_documentazione is the alternative. |
patent-box-tracker.locale |
string | it |
Dossier locale. it ships in v1.0; en and others planned for v1.1. |
patent-box-tracker.excluded_authors |
array | ['dependabot[bot]', 'renovate[bot]', 'github-actions[bot]'] |
Author email substrings skipped during the git walk so bot-authored commits do not count as qualified R&D. |
patent-box-tracker.renderer.driver |
string | browsershot |
browsershot (Chromium) or dompdf fallback. |
patent-box-tracker.renderer.browsershot.chrome_path |
string|null | null |
Override the headless Chromium binary path; defaults to Browsershot's auto-detection. |
patent-box-tracker.renderer.browsershot.timeout |
int | 60 |
Browsershot render timeout (seconds). |
patent-box-tracker.api.enabled |
bool | false |
Mount the HTTP API v1 routes when true. |
patent-box-tracker.api.prefix |
string | api/patent-box |
URL prefix for the API. |
patent-box-tracker.api.middleware |
array | ['api'] |
Middleware chain applied to the API group (auth, etc.). |
patent-box-tracker.api.rate_limiter |
string | 60,1 |
"max,minutes" passed to Laravel's throttle: middleware. |
patent-box-tracker.api.auth_token |
string|null | env('PATENT_BOX_API_TOKEN') |
Optional bearer/header token gate. Disabled when null. |
Every key is also overridable per-call via the fluent builder or the YAML cross-repo config.
Architecture
flowchart LR
subgraph Inputs[Inputs]
Repos[(Git repos)]
Docs[(docs/ + plans/)]
Yaml[/cross-repo YAML/]
Manual[/manual_supplement/]
end
subgraph Collectors[Evidence collectors β pluggable]
Git[GitSourceCollector]
Ai[AiAttributionExtractor]
Design[DesignDocCollector]
Branch[BranchSemanticsCollector]
end
subgraph Pipeline[Pipeline]
Batch[ClassifierBatcher]
Clf[CommitClassifier β temp=0, fixed seed]
Hash[HashChainBuilder]
Golden[GoldenSetValidator β release gate]
end
subgraph Storage[Storage]
TS[(tracking_sessions)]
TC[(tracked_commits)]
TE[(tracked_evidence)]
TD[(tracked_dossiers)]
end
subgraph Renderers[Renderers]
Pdf[PdfDossierRenderer β Browsershot + DomPDF]
Json[JsonDossierRenderer β hash-chain signed]
end
subgraph Surfaces[Delivery surfaces]
Cli[Artisan + fluent builder]
Api[HTTP API v1 β opt-in]
Admin[Admin web panel β separate package]
end
subgraph LLM[laravel/ai SDK]
Sdk[(any provider β Regolo / OpenAI / Anthropic / Gemini)]
end
Repos --> Git
Repos --> Ai
Docs --> Design
Repos --> Branch
Yaml --> Batch
Manual --> Pdf
Git --> Batch
Ai --> Batch
Design --> Batch
Branch --> Batch
Batch --> Clf
Clf <--> Sdk
Clf --> Hash
Hash --> TC
TC --> Golden
TC --> Pdf
TC --> Json
TS --> Pdf
TE --> Pdf
Pdf --> TD
Json --> TD
TD --> Cli
TD --> Api
Api --> Admin
Loading
A few notes on the architecture:
- Collectors are independent. Each implements
EvidenceCollectorwith a non-overlappingsupports()predicate. v1.0 ships four; future versions add more without breaking the registry. - The classifier is the only LLM-touching component. Everything upstream is deterministic git + filesystem walk. Everything downstream is template rendering + cryptographic hashing. The non-determinism budget is bounded to one component, and that component runs at
temperature=0with a fixed seed. - Storage is the audit trail.
tracking_sessionsrecords the classifier provider / model / seed;tracked_commitsrecords the hash chain;tracked_dossiersrecords the SHA-256 of every rendered artefact. The dossier you hand to Agenzia delle Entrate is reproducible from the same DB at any point within the 5-year audit window. - Three delivery surfaces, one core. CLI (Artisan + fluent builder), HTTP API v1, and the optional companion admin web panel all read/write the same storage and the same dossier artefacts.
π AI vibe-coding pack included
Every Padosoft package ships with the same
.claude/pack, so AI-driven contribution stays consistent across the family.
Every release of this package includes the Padosoft Claude pack under the .claude/ directory: the same skills, rules, agents, and slash-commands the Padosoft team uses internally to keep AI-driven development consistent across all our repos. The moment you composer require padosoft/laravel-patent-box-tracker and open the project in Claude Code, the agent automatically picks up the pack and applies it.
What ships in the pack
.claude/
βββ skills/
β βββ patent-box-enterprise/ β macro-branch + subtask-PR + Copilot review loop
β βββ copilot-pr-review-loop/ β R36: 9-step PR flow (--reviewer copilot,
β β wait CI green, wait Copilot review,
β β fix, re-CI, merge only when both green)
β βββ pre-push-self-review/ β diff self-review against recurring footguns
β βββ test-count-readme-sync/ β keep README test counts honest
β βββ create-api-endpoint/ β Laravel 13 thin-controller pipeline
β βββ create-controller/ β controller patterns (web/API/admin)
β βββ create-service/ β service/action with DTO boundaries
β βββ create-test/ β unit/feature/E2E selection
β βββ create-crud-backend/ β standard CRUD scaffolding
β βββ create-filesystem-helpers/ β disk + path + retention helpers
β βββ admin-interface-backend/ β admin page backend pipeline
β βββ admin-interface-frontend/ β admin page frontend modules
β βββ admin-interface-component-audit/β REUSE/EXTEND/CREATE decisions
β βββ create-admin-interface/ β orchestrator for full admin pages
β βββ playwright-enterprise-tester/ β E2E discovery β authoring β diagnose β report
β βββ review-pr-comments/ β classify and route PR review feedback
βββ commands/ β /create-job, /create-setting, /domain-scaffold,
β /domain-service, /pagespeed-review, /playwright-tester
βββ rules/ β Padosoft baseline coding rules (Laravel + general + Playwright)
βββ agents/
βββ admin-interface-architect β admin design assistant
βββ playwright-enterprise-tester β Playwright sub-agent
Why this matters
When a contributor (you, a team-mate, an open-source PR author) opens this repo in Claude Code:
- The agent reads the pack on session start.
- The R36 PR-review skill kicks in automatically the first time the contributor types
gh pr create. The agent uses--reviewer copilot-pull-request-reviewer, waits for CI, waits for Copilot review, addresses comments, re-checks CI, and only merges when both gates are green. - Future skills (style enforcement, security review, release-note generator, ...) plug into the same pack with zero configuration on the consumer side.
The result: you get the Padosoft AI engineering culture in the same composer require that gets you the Patent Box tracker.
Opting out
Do not want the pack? Add .claude/ to your .gitignore (or delete it locally). The package code under src/ works completely independently of the pack β the pack is purely a developer-experience layer for repos that use Claude Code.
Want to contribute a skill?
The same pack is shared across padosoft/laravel-ai-regolo, padosoft/laravel-flow, padosoft/eval-harness, padosoft/laravel-pii-redactor, padosoft/laravel-patent-box-tracker, and padosoft/laravel-patent-box-tracker-admin β open a PR on any of those repos and we will sync the skill across the family.
Testing
Default suite β offline, zero cost, runs everywhere
The package ships a comprehensive offline test suite that runs against Http::fake() for the LLM, recorded git fixtures for the repo walks, and synthetic docs/ trees for the design-doc correlator. The test suite never hits a real API and is safe to run in CI on every PR.
composer install vendor/bin/phpunit
Coverage breakdown:
| Suite | What it covers |
|---|---|
CommitClassifierTest |
Fixture commit + canned LLM response β expected CommitClassification. Http::fake() only. |
GitSourceCollectorTest |
Recorded bare repo tests/fixtures/repos/synthetic-r-and-d.git (30 commits, 5 phases) β exact metadata. |
AiAttributionExtractorTest |
12 commit-message variants β expected attribution flag (human / ai_assisted / ai_authored / mixed). |
DesignDocCollectorTest |
Synthetic docs/ tree β expected evidence-link graph (filename / slug / date-proximity matches). |
BranchSemanticsCollectorTest |
Branch-name patterns (feature/v4.0-W*, chore/, fix/) β expected semantics. |
HashChainBuilderTest |
Same input β same chain. Tampering one commit breaks the chain at that exact position. |
JsonDossierRendererTest |
Round-trip a synthetic session β JSON β re-parse β re-render produces byte-identical output. |
GoldenSetValidatorTest |
Synthetic golden set + synthetic classifier outputs β F1 score matches a hand-computed value. |
TrackCommandTest |
php artisan patent-box:track <fixture-repo> end-to-end with Http::fake(). No live HTTP calls. |
CrossRepoCommandTest |
YAML config + 3 fixture repos β one session with 3 repository-roles, cross-repo summary correct. |
RenderCommandTest |
Pre-populated session β PDF exists, page count > 1, JSON sidecar valid against schema. |
Api/*Test |
Full HTTP API v1 coverage β auth gate, rate limit, envelope contract, error taxonomy, integrity check. |
ApiContractFixturesTest |
Fixture-driven contract tests guarantee /v1 response shape stability across releases. |
StandaloneAgnosticTest |
Architecture test β package source contains zero KnowledgeDocument / KbSearchService / lopadova/* references. |
CI matrix: PHP 8.3 / 8.4 / 8.5 Γ Laravel 12 / 13 (6 cells), plus a separate static-analysis job that runs PHPStan and Pint and a dedicated API-contract job.
Running the live test suite (against a real LLM provider)
If you want to verify behaviour against real provider servers β for example you are validating a model upgrade, an open-source contributor confirming wire compatibility before tagging a release, or a downstream adopter doing a pre-deploy smoke-test β the package ships a dedicated Live PHPUnit testsuite that hits a real laravel/ai provider end-to-end.
The live suite is opt-in by design:
- A fresh
git clone+composer install+vendor/bin/phpunitruns only the offline suite. No accidental cost. - The
Livesuite self-skips whenPATENT_BOX_LIVE_API_KEYis missing, so it cannot accidentally fail a CI job that does not have credentials. - The CI matrix on this repo runs only the offline suite. Live tests run only when invoked explicitly with
--testsuite Live.
1. Configure the environment
export PATENT_BOX_LIVE_API_KEY=rg_live_...
Optional overrides:
export PATENT_BOX_LIVE_PROVIDER=regolo export PATENT_BOX_LIVE_MODEL=claude-sonnet-4-6 export PATENT_BOX_LIVE_FIXTURE_REPO=/path/to/a/small/test/repo
On Windows PowerShell:
$env:PATENT_BOX_LIVE_API_KEY = "rg_live_..."
2. Run the live suite
vendor/bin/phpunit --testsuite Live
β¦or with the testdox formatter so each scenario prints by name:
vendor/bin/phpunit --testsuite Live --testdox
What the live suite verifies
| File | What it asserts on the real provider | Cost |
|---|---|---|
ClassifierLiveTest |
5 hand-picked real feature/v4.x commits β β₯ 80% match against the golden labels. |
~β¬0.05 |
RendererLiveTest |
Generates a real PDF and validates it opens in pdf-parser without errors. |
minimal |
Total cost per run: well under β¬0.10 with the default small-model selection.
CI policy
The live suite is never run from this package's .github/workflows/ci.yml. To run it in your own pipeline:
- name: Live verification (manual workflow_dispatch only) if: env.PATENT_BOX_LIVE_API_KEY != '' env: PATENT_BOX_LIVE_API_KEY: ${{ secrets.PATENT_BOX_LIVE_API_KEY }} run: vendor/bin/phpunit --testsuite Live
Roadmap
| Version | Status | Highlights |
|---|---|---|
| v1.0 | β shipped | 4 evidence collectors + deterministic LLM classifier + Italian PDF + JSON sidecar + hash-chain tamper evidence + cross-repo YAML orchestration + cost-cap guard + hand-graded golden set β₯ 80% F1 + opt-in Live testsuite + AI vibe-coding pack + stable HTTP API v1 + companion admin web panel (separate package). |
| v1.1 | planned | Time-tracking integrations (Toggl / Harvest / RescueTime / Clockify). Calendar collector for off-keyboard R&D. Live terminal session capture (Cursor / Claude Code). Token-by-token AI-vs-human line-level attribution. English locale for the dossier template. |
| v1.2 | planned | Direct UIBM / SIAE / EPO API integration β auto-link IP filings to dossier entries. SSE / websocket live progress for long classification runs. Cursor pagination for large sessions. |
| v2.0 | tracking | Tax-jurisdiction support beyond Italy (UK Patent Box, Irish Knowledge Box, German FuE-Zulage). Multi-tenant SaaS deployment. Pluggable jurisdictional dossier templates. |
Open issues and feature votes: github.com/padosoft/laravel-patent-box-tracker/issues.
Contributing
Contributions are welcome β bug reports, test cases, new evidence collectors, golden-set commits with commercialista-validated labels, documentation polish.
- Fork the repository.
- Create a feature branch (
feature/your-thing) targetingmain. - Run
vendor/bin/phpunitandvendor/bin/pint --testlocally. - Open a PR with a clear description, a test that covers the change, and (if you touch the classifier prompt) a re-run of the golden-set validator showing F1 β₯ 80%.
We follow the project conventions documented in CONTRIBUTING.md. Please respect the existing concern split (src/Sources/, src/Classifier/, src/Renderers/, src/Hash/, src/Http/) when adding capabilities β it keeps the package legible and audit-friendly.
Adding a new evidence collector
- Implement
Padosoft\PatentBoxTracker\Sources\EvidenceCollector. - Make sure your
supports()predicate does not overlap with any existing collector β the boot-time mutex check (R23) will refuse to register otherwise. - Tag the FQCN with
patent-box.collectorsin your service provider. - Add a Unit test that exercises the collector against a synthetic fixture.
Security
Found a security issue? Please do not open a public issue. Email lorenzo.padovani@padosoft.com instead. We follow standard responsible-disclosure timelines documented in SECURITY.md.
Special note on dossier integrity: if you discover a way to mutate a tracked dossier without breaking the hash chain, this is a critical finding β please flag it as such in the disclosure. The chain is the audit-trail anchor; an integrity break is a release blocker.
License & credits
Apache-2.0 β see LICENSE.
Built and maintained by Padosoft, authored by Lorenzo Padovani. Initially developed alongside AskMyDocs β and dogfooded against Padosoft's own FY2026 Italian Patent Box dossier β but the package is fully standalone agnostic: no AskMyDocs dependency, no Padosoft proprietary glue. It works in any Laravel 12/13 application that has laravel/ai installed.
Companion package:
padosoft/laravel-patent-box-tracker-adminβ production-grade Laravel admin web panel on top of the v1 HTTP API. Optional, drop-in.
Sister packages in the Padosoft AI stack:
padosoft/laravel-ai-regoloβ first-class Regolo (Italian sovereign AI) provider forlaravel/ai.padosoft/laravel-flowβ saga / workflow orchestration for Laravel.padosoft/eval-harnessβ RAG + agent evaluation harness.padosoft/laravel-pii-redactorβ PII redaction middleware for AI prompts.
Each is independently usable. None requires the others. Pick what you need.
Made with β in Italy by Padosoft.