Repository navigation
Open Questions
Numbered so they can be referenced from other pages and from issues. Anything resolved here graduates to an ADR in Decisions and stays listed below with its answer, so the reasoning is not lost.
Separate discussion — deliberately not decided as part of the initial scope.
JVM startup cost is paid on every invocation, which is exactly the wrong shape for a CLI used interactively, in shell completion and in loops over a CSV. A native image would give near-instant startup and a single binary with no JRE requirement.
Against it: an additional and considerably slower build, per-platform build infrastructure (macOS arm64/x64,
Linux, Windows), and reflection configuration for everything reflective — picocli, JAXB-generated data types,
XML signature handling, the JCE/TLS stack and DNS resolution are all candidates for trouble. Some of those are
notoriously awkward under native-image.
No project in this ecosystem currently builds a native image, so this would be new ground.
Sub-questions: is native image an additional artefact or the primary one? Which platforms are supported? Does
the effort still pay off given Java 25's ahead-of-time class loading and linking (see ADR-005)?
> TODO(verify): measure plain JVM startup for a trivial command before treating startup time as a problem worth this much effort
Candidates and the trade-off are set out in Configuration: TOML (readable, comments, typed, new dependency), Java properties (no new dependency, ecosystem-native, poor at nesting), YAML (familiar, but whitespace-sensitive and easy to get subtly wrong), JSON (no comments — disqualifying for a hand-edited file).
Depends on: which dependency is acceptable, and whether profiles need nesting deeper than one level.
> TODO(verify): whether the ph-commons configuration facility already provides a suitable file format and precedence handling that should simply be reused
See ADR-006. Consistent with norma-cli, kaltblut-cli,
ph-redact-cli, the en16931-*-cli tools and phoss-peppol-mcp (picocli 4.7.7).
Remaining detail: pin the version locally or inherit it from a shared parent POM property.
Parsing and validating an MLS response is useful for diagnostics and low-risk, so peppol mls parse and
peppol mls validate are accepted.
Generating one is a different matter: an MLS response is a statement made by a receiving party about a message it processed. A CLI that can emit one invites hand-crafted statuses being sent outside the AP that actually handled the message, which is a correctness and accountability problem rather than a convenience.
Decision: parse only. peppol mls generate is deferred — there is no present need for it. The builders
(PeppolMLSBuilder and friends) are in place, so it can be reconsidered cheaply if implementers testing their
own MLS handling ask for it, most likely behind an explicit "for testing" flag.
> TODO(verify): the exact MLS specification name and version
Code lists ship with the distribution and are updated by upgrading the tool. No download, no cache refresh, no TTL.
This follows from the data's shape rather than from preference: the code lists are exposed at runtime only as
generated enums, and there will be no shared library for reading code list data at runtime. peppol codelist diff
and peppol codelist update are therefore rejected in the Feature Catalogue.
The upside is real: every code list command works offline, unconditionally, with nothing to invalidate and no
unattended run whose behaviour depends on a background download. peppol codelist version reports the bundled
version per kind, so a user can always see what they have — and each code list is versioned independently, so
the versions are allowed to differ and the tool must not treat that as an error.
Remaining minor question: should the tool warn when its bundled code lists are older than some threshold? That
needs no new mechanism, only a build-time timestamp. > TODO(decide): warn on stale bundled code lists, or leave it to the user to notice?
See ADR-005. Note that the shared parent POM currently defaults to
Java 17, so this project overrides the java.version property.
Remaining detail: whether the distribution archive should bundle a runtime (via jlink) so users do not have to
install Java 25 themselves.
See ADR-008. The repository already contains the Apache 2.0 LICENSE file,
and every project this one builds on uses the same licence.
Remaining, and genuinely separate from the choice itself: a licence review of the transitive dependency set once
the module list is fixed. Everything directly planned is Apache 2.0 (picocli, ph-commons, peppol-commons,
peppol-directory-client, phorm-client), but the SOAP/JAX-WS stack pulled in by peppol-sml-client and the
dnsjava dependency are the ones to check, since neither is a phax project.
> TODO(verify): run a licence report over the resolved dependency tree before the first release.
Options: (a) tier 1 — tested in CI, .cmd/.ps1 launcher, PowerShell completion, Windows path and console
handling, %APPDATA% config location; (b) best effort — it should work, but is untested and unsupported;
(c) not supported.
Specific Windows concerns: ANSI colour support in the console host, %APPDATA% versus XDG config discovery,
path separators in bulk CSV input, keystore access, and whether the Windows certificate store should be used as
a truststore source.
Current inclination: (a), because support engineers are a target audience and frequently work on Windows.
> TODO(decide): confirm the intended support level, since it determines CI cost from the start
Typing a 200-character document type identifier is the single worst part of the current tooling experience, so aliases are clearly worth having. The question is where they come from.
Derived from code list display names — free, always complete, and automatically covers new document types.
But verified problems: 16 of the 321 display names in v9.7 are duplicated (mostly busdox-docid-qns versus
peppol-doctype-wildcard variants), and display names are not guaranteed stable across code list versions. An
alias that silently changes meaning after an upgrade is worse than no alias.
Curated in the CLI — a hand-maintained table of short, stable names (bis3-invoice, bis3-creditnote) for
the dozen or so document types people actually type. Stable by construction and unambiguous, but needs
maintenance and will not cover everything.
Both — a curated table taking precedence, falling back to derived display names, with ambiguity always an
error rather than a guess. Probably the right answer; it needs a decision on who maintains the curated table and
whether it belongs in peppol-commons rather than in the CLI, since the problem is not CLI-specific.
See the alias rules in CLI Conventions and the feature entries in Feature Catalogue.
SMP 1.4.0 §3 defines no create/update/delete interface, so the write API peppol-smp-client speaks is in practice
the phoss-SMP one. Rather than hide that behind a generic smp area, the write commands live under their own
phoss-smp area — see CLI Conventions and the
Feature Catalogue. peppol smp … stays the specified read interface that works against any
conformant SMP.
That makes the portability boundary visible instead of documented-in-a-footnote, and leaves room for a future
peppol <other>-smp area without renaming anything. Other implementations that happen to expose the same API are
likely to work, but the tool promises nothing about them.
Both resolved. The area is spelled phoss-smp, with phosssmp accepted as an alias. And the tool does
detect an incompatible SMP up front, via the /smp-status preflight — chiefly the
smp.writable-rest-api.enabled field — while treating an absent status response as inconclusive rather than
negative. Both are recorded in the Feature Catalogue.
These came out of drafting and need an owner:
-
Default network.Resolved:--networkdefaults toprod. Almost all use is looking up real participants, so production is what the user meant;--network testis the deliberate act. The consequence is that write safety rests entirely on the write rails — confirmation,--dry-run, and naming the resolved network in the prompt — rather than on the network selector. See CLI Conventions. -
Write command safety. Is
--dry-runthe default for write commands, with--committo execute? This matters more now that the network defaults toprod. -
Command naming for the flagship check.
peppol smp can-receivereads well; is there a more conventional name for what operators actually call this check? - JSON Schema publication. Publish a schema per command, or document the shapes in the wiki only?
- Telemetry. Proposed answer: none, ever, with no opt-in. Worth recording as an ADR so it is never revisited casually.
- Deprecation handling. Does using a deprecated participant scheme or document type warrant a warning at exit 0, or its own exit code?
peppol-cli — licensed under the Apache License, Version 2.0.
Not an official OpenPeppol tool. This is an independent open source project and is neither endorsed by nor affiliated with OpenPeppol AISBL. "Peppol" is a trademark of OpenPeppol AISBL.
Status: planning
Overview
Design
Decisions
Reference