diff --git a/.codex/skills/fctl-v4-architecture/SKILL.md b/.codex/skills/fctl-v4-architecture/SKILL.md new file mode 100644 index 00000000..58e1a03b --- /dev/null +++ b/.codex/skills/fctl-v4-architecture/SKILL.md @@ -0,0 +1,65 @@ +--- +name: fctl-v4-architecture +description: Use when working on the Formance fctl v4 CLI architecture, contexts, authentication, API version resolution, compatibility manifests, command design, or migrations from fctl v3. This skill keeps future work aligned with the repository's v4 RFC and ADRs. +--- + +# fctl v4 Architecture Skill + +Use this skill for any `fctl` v4 design or implementation work. + +## Required Reading + +Before changing v4 architecture or commands, read these repository files: + +- `docs/rfcs/0001-fctl-v4-architecture.md` +- `docs/cli-v4/command-design.md` +- `docs/cli-v4/compatibility-manifest.md` +- `todos/01-v4-isolated-skeleton.md` + +Read ADRs as needed: + +- `docs/adr/0001-contexts-as-primary-target.md` +- `docs/adr/0002-auth-is-decoupled-from-cloud.md` +- `docs/adr/0003-api-version-resolution.md` +- `docs/adr/0004-cobra-thin-runtime.md` +- `docs/adr/0005-build-v4-in-isolated-directory.md` + +## Core Rules + +- Do not make Formance Cloud membership required for stack commands. +- Treat contexts as the primary target selector. +- Keep auth as a target-local strategy. +- Use `/versions` plus the compatibility manifest to infer supported API namespaces. +- Commands express product intent; they must not expose API versions as the primary UX. +- Keep CLI flags canonical and product-oriented; map them to version-specific SDK request fields internally. +- Keep Cobra thin. Runtime concerns belong in typed internal packages. +- Build the rewrite under `v4/` until the explicit cutover goal. +- Follow `todos/*.md` in order unless the user explicitly reprioritizes. +- Commit after each logical step. + +## CLI Rendering Policy + +- Human `plain` output must go through shared rendering helpers instead of writing raw strings directly to `cmd.OutOrStdout()`. +- Use `styledSuccessLine` for successful mutations, `writeStyledKeyValues` for detail views, `writeStyledRows`/`v4render.Table` for lists, `styledEmptyLine` for empty states, and `styledInfoLine` for supporting metadata such as API versions. +- Keep scriptability intact: JSON/YAML output must stay unstyled, non-TTY plain output must remain stable, and ANSI styling must only be emitted for terminal output. +- Direct writes to `cmd.OutOrStdout()` are allowed only for raw payloads such as archives, manifests, logs, or compatibility-preserving fallback paths that are explicitly tracked by tests. +- When adding or touching a command renderer, remove it from the raw-output baseline in `v4/cmd/rendering_policy_test.go` and route its output through the shared helpers. + +## Implementation Shape + +Prefer this package split under `v4/` during the transition: + +```text +v4/cmd/ Cobra declarations only +v4/internal/runtime/ target resolution, auth, versions, API selection +v4/internal/config/ contexts, defaults, XDG paths, migrations +v4/internal/credentials/ keyring and insecure fallback +v4/internal/capabilities generated manifest and compatibility ranges +v4/internal/commands/ typed product command implementations +v4/internal/render/ table, json, yaml, markdown +v4/internal/prompt/ optional interactive flows +``` + +## Validation + +For command behavior, prefer integration-style tests that execute real CLI commands and assert stdout, stderr, exit codes, and config files. Keep scriptability and non-interactive usage as first-class requirements. diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..6f5c7ae9 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,20 @@ +# fctl v4 Guidance + +Before working on the next major CLI architecture, read: + +- `docs/rfcs/0001-fctl-v4-architecture.md` +- `docs/cli-v4/command-design.md` +- `docs/cli-v4/compatibility-manifest.md` +- `todos/01-v4-isolated-skeleton.md` + +Core rules: + +- Do not couple stack commands to Formance Cloud membership. +- Treat context, target, auth, capabilities, API version, and rendering as separate concepts. +- Commands express product intent; API version selection belongs in the runtime. +- Use `/versions` plus the generated compatibility manifest to select the best supported SDK namespace. +- Keep Cobra as a thin parser/router; keep business logic in typed internal packages. +- Store credentials in a keyring when possible; keep config files free of long-lived secrets. +- Build the rewrite under `v4/` until the explicit cutover goal. +- Follow `todos/*.md` in order unless the user explicitly reprioritizes. +- Commit after each logical step when implementing v4 work. diff --git a/docs/adr/0001-contexts-as-primary-target.md b/docs/adr/0001-contexts-as-primary-target.md new file mode 100644 index 00000000..4b48e7e4 --- /dev/null +++ b/docs/adr/0001-contexts-as-primary-target.md @@ -0,0 +1,18 @@ +# ADR 0001: Contexts Are The Primary Target Selector + +Status: Accepted for v4 planning + +## Context + +The current profile model is centered on Formance Cloud membership. That makes stack usage depend on Cloud identity even when the user wants to talk to a local or self-hosted stack. + +## Decision + +Use named contexts as the primary target selector. A context describes the target endpoint, authentication method, defaults, and API version policy. + +## Consequences + +- Stack commands can run without Cloud membership. +- Cloud workflows remain possible through Cloud-specific context kinds. +- `--context` and `FCTL_CONTEXT` can override the current context. +- Context export/import becomes possible later. diff --git a/docs/adr/0002-auth-is-decoupled-from-cloud.md b/docs/adr/0002-auth-is-decoupled-from-cloud.md new file mode 100644 index 00000000..3741e0e8 --- /dev/null +++ b/docs/adr/0002-auth-is-decoupled-from-cloud.md @@ -0,0 +1,18 @@ +# ADR 0002: Authentication Is Decoupled From Cloud + +Status: Accepted for v4 planning + +## Context + +The current CLI authenticates through a membership relying party. This prevents a clean local and self-hosted user experience. + +## Decision + +Model authentication as a target-local strategy. Supported strategies should include Cloud device flow, generic OIDC, client credentials, token from stdin/env, and explicit no-auth development mode. + +## Consequences + +- Local stacks can use `client_credentials` with default development clients. +- Self-hosted stacks can use their own OIDC issuer. +- CI can use tokens or client credentials without browser flows. +- Cloud membership becomes one auth strategy, not the root abstraction. diff --git a/docs/adr/0003-api-version-resolution.md b/docs/adr/0003-api-version-resolution.md new file mode 100644 index 00000000..71630488 --- /dev/null +++ b/docs/adr/0003-api-version-resolution.md @@ -0,0 +1,18 @@ +# ADR 0003: API Version Resolution Belongs In Runtime + +Status: Accepted for v4 planning + +## Context + +The public SDK exposes versioned namespaces such as `Ledger.V1`, `Ledger.V2`, and `Payments.V3`. The stack exposes `/versions`, but not a full capabilities endpoint. + +## Decision + +Commands declare product features and available handlers. The runtime calls `/versions`, maps component versions to supported API namespaces, intersects that with command handlers, and selects the best compatible handler. + +## Consequences + +- Commands do not hardcode the oldest API namespace. +- New endpoints can appear as normal product commands and fail cleanly on older targets. +- A small manual compatibility table is still required for component version ranges. +- Most operation metadata can be generated from the OpenAPI spec. diff --git a/docs/adr/0004-cobra-thin-runtime.md b/docs/adr/0004-cobra-thin-runtime.md new file mode 100644 index 00000000..5d0f4de4 --- /dev/null +++ b/docs/adr/0004-cobra-thin-runtime.md @@ -0,0 +1,18 @@ +# ADR 0004: Keep Cobra Thin + +Status: Accepted for v4 planning + +## Context + +Cobra is widely used and already present in `fctl`, but current command implementations mix parsing, auth, client construction, API selection, and rendering. + +## Decision + +Keep Cobra for routing, flags, help, aliases, deprecations, and shell completions. Move target resolution, authentication, API versioning, and business logic into typed internal packages. + +## Consequences + +- Existing Cobra knowledge remains useful. +- Command files become smaller and easier to test. +- The runtime can be tested independently from Cobra. +- The CLI can keep a stable user experience while API versions evolve. diff --git a/docs/adr/0005-build-v4-in-isolated-directory.md b/docs/adr/0005-build-v4-in-isolated-directory.md new file mode 100644 index 00000000..2964e4c6 --- /dev/null +++ b/docs/adr/0005-build-v4-in-isolated-directory.md @@ -0,0 +1,19 @@ +# ADR 0005: Build v4 In An Isolated Directory + +Status: Accepted for v4 planning + +## Context + +`fctl` v4 is intended to be a near-rewrite. The existing v3 code remains useful as a behavioral reference during implementation and review. + +## Decision + +Build the new CLI under a top-level `v4/` directory during the transition. Keep the existing root implementation intact until v4 has reached feature parity or an explicit cutover point. + +## Consequences + +- v3 remains available for comparison while v4 is built. +- Review is easier because new code is isolated from old code. +- The v4 module can start with a clean package layout. +- The final cutover will delete or archive the old root implementation and move the v4 implementation to the root. +- Build, release, and test commands must be explicit about whether they target v3 root or `v4/`. diff --git a/docs/cli-v4/README.md b/docs/cli-v4/README.md new file mode 100644 index 00000000..67f4192c --- /dev/null +++ b/docs/cli-v4/README.md @@ -0,0 +1,21 @@ +# fctl v4 Documentation + +The v4 CLI is implemented under `v4/`, but its documentation lives here so it +can be reviewed with the repository-level architecture docs. + +Read these in order when onboarding to v4: + +1. `../rfcs/0001-fctl-v4-architecture.md` for the target architecture. +2. `../adr/` for accepted decisions. +3. `command-design.md` for command shape and Cobra boundaries. +4. `config-format.md` for profiles, contexts, and credential storage. +5. `runtime-behavior.md` for current login, scopes, stack waits, rendering, and + debug behavior. +6. `command-reference.md` for visible command families. +7. `migration-v3-v4.md` and `compatibility-aliases.md` for v3 compatibility. +8. `testing-strategy.md` for local and CI validation. +9. `implementation-audit.md` for current implementation status and known gaps. +10. `cutover-plan.md` for the future move out of `v4/`. + +Keep `command-reference.md` and `runtime-behavior.md` aligned with Cobra help and +the manual command audit whenever commands are added, hidden, or renamed. diff --git a/docs/cli-v4/command-design.md b/docs/cli-v4/command-design.md new file mode 100644 index 00000000..a3d01648 --- /dev/null +++ b/docs/cli-v4/command-design.md @@ -0,0 +1,77 @@ +# fctl v4 Command Design + +Commands should express Formance product intent, not OpenAPI or SDK structure. + +Prefer: + +```bash +fctl ledger transactions list +fctl ledger transactions revert +fctl ledger schemas insert +``` + +Avoid: + +```bash +fctl ledger v2 transactions list +fctl ledger transactions list-v2 +``` + +## Canonical Inputs + +Each command should parse into a version-independent input model. + +```go +type ListTransactionsInput struct { + Ledger string + AccountAddress string + PageSize int64 +} +``` + +Version-specific adapters convert that model into generated SDK request types. + +```go +func toLedgerV1(input ListTransactionsInput) operations.ListTransactionsRequest +func toLedgerV2(input ListTransactionsInput) operations.V2ListTransactionsRequest +``` + +## Renamed API Parameters + +If API v1 calls a field `account` and API v2 calls it `address`, but the CLI concept is the same, expose one canonical flag. + +```bash +fctl ledger transactions list --account users:123 +``` + +Keep aliases only for CLI compatibility, not because generated API names changed. + +## Version-Specific Features + +A command can exist even if only newer targets support it. + +```bash +fctl ledger transactions explain +``` + +If the current target only supports an older Ledger API, return: + +```text +ledger transactions explain requires Ledger >= 3.0.0. +Current target runs Ledger 2.3.4. +``` + +If the command requires an API operation that is not exposed by the public stack +spec or the current SDK, keep it hidden from the visible command surface until +the contract is explicit. `ledger transactions explain` currently follows this +rule. + +## Help Text + +Help should be stable and product-oriented. For flags or commands requiring newer APIs, include capability notes: + +```text +--include-descendants Include child accounts (requires ledger API v2+) +``` + +Context-aware help can be added later, but the base help should remain useful without network calls. diff --git a/docs/cli-v4/command-reference.md b/docs/cli-v4/command-reference.md new file mode 100644 index 00000000..b9b6984b --- /dev/null +++ b/docs/cli-v4/command-reference.md @@ -0,0 +1,302 @@ +# fctl v4 Command Reference + +This reference lists the current canonical v4 command families implemented under +`v4/`. It tracks visible commands only. Hidden compatibility commands and +temporarily disabled command families are documented separately below. + +The latest manual command audit covered 193 visible executable leaf commands. +When this file changes, verify it against Cobra help before committing. + +## Global Flags + +- `--profile ` +- `--context ` hidden deprecated alias for `--profile` +- `--organization ` Cloud or EE organization override +- `--stack ` Cloud or EE stack override +- `--config-dir `, `-c ` +- `--credential-dir ` +- `--output plain|json|yaml` +- `--non-interactive` +- `--insecure-tls` +- `--debug`, `-d` +- `--no-color` + +## Target and Configuration + +- `fctl login` +- `fctl login --target cloud --client-id --client-secret-stdin` +- `fctl login --target ee --membership-url --client-id --client-secret-stdin` +- `fctl login --target open-source --stack-url ` +- `fctl logout` +- `fctl whoami` +- `fctl profile create stack --stack-url ` +- `fctl profile create cloud --cloud-url ` +- `fctl profile create cloud-stack --cloud-url --organization --stack ` +- `fctl profile list` +- `fctl profile show ` +- `fctl profile use ` +- `fctl profile rename ` +- `fctl profile delete --confirm` +- `fctl profile set [name] --organization --stack --default-ledger ` +- `fctl profile unset-defaults [name] --confirm` +- `fctl config migrate-v3` +- `fctl setup` +- `fctl target inspect` +- `fctl target proxy --port 55001` +- `fctl stack proxy --port 55001` deprecated alias for `fctl target proxy` + +`context` and `session` commands remain hidden implementation/compatibility +commands for now. New user flows should use `login`, `logout`, `whoami`, and +`profile`. + +## Cloud + +- `fctl cloud me show` +- `fctl cloud me invitations list` +- `fctl cloud me invitations accept --confirm` +- `fctl cloud me invitations decline --confirm` +- `fctl cloud ui --print` +- `fctl cloud organizations create ` +- `fctl cloud organizations list` +- `fctl cloud organizations show ` +- `fctl cloud organizations history [organization-id] --action --user-id --data key=value` +- `fctl cloud organizations update --name ` +- `fctl cloud organizations delete --confirm` +- `fctl cloud organizations applications list --organization ` +- `fctl cloud organizations applications show --organization ` +- `fctl cloud organizations authentication-provider show --organization ` +- `fctl cloud organizations authentication-provider configure --type --name --client-id --client-secret-stdin --organization ` +- `fctl cloud organizations authentication-provider delete --organization --confirm` +- `fctl cloud organizations oauth-clients create --name --organization --confirm` +- `fctl cloud organizations oauth-clients list --organization ` +- `fctl cloud organizations oauth-clients show --organization ` +- `fctl cloud organizations oauth-clients update --name --organization --confirm` +- `fctl cloud organizations oauth-clients delete --organization --confirm` +- `fctl cloud organizations invitations list --organization ` +- `fctl cloud organizations invitations send --organization ` +- `fctl cloud organizations invitations delete --organization --confirm` +- `fctl cloud organizations users list --organization ` +- `fctl cloud organizations users show --organization ` +- `fctl cloud organizations users link --organization --policy-id ` +- `fctl cloud organizations users unlink --organization --confirm` +- `fctl cloud organizations policies create --organization ` +- `fctl cloud organizations policies list --organization ` +- `fctl cloud organizations policies show --organization ` +- `fctl cloud organizations policies update --organization --name ` +- `fctl cloud organizations policies delete --organization --confirm` +- `fctl cloud organizations policies add-scope --organization ` +- `fctl cloud organizations policies remove-scope --organization --confirm` +- `fctl cloud regions create --organization ` +- `fctl cloud regions list --organization ` +- `fctl cloud regions show --organization ` +- `fctl cloud regions delete --organization --confirm` + +Cloud commands require a `cloud` or `cloud-stack` context. They are not required +for direct local or self-hosted stack commands. The root `ui` command is a +hidden deprecated alias for `cloud ui`. + +## Cloud Stacks + +- `fctl cloud stacks create --region ` +- `fctl cloud stacks list --organization ` +- `fctl cloud stacks show --organization ` +- `fctl cloud stacks update --name ` +- `fctl cloud stacks delete --confirm` +- `fctl cloud stacks enable ` +- `fctl cloud stacks disable --confirm` +- `fctl cloud stacks restore --confirm` +- `fctl cloud stacks upgrade --version --confirm` +- `fctl cloud stacks history ` +- `fctl cloud stacks users list ` +- `fctl cloud stacks users link --policy-id ` +- `fctl cloud stacks users unlink --confirm` +- `fctl cloud stacks modules list ` +- `fctl cloud stacks modules enable ` +- `fctl cloud stacks modules disable --confirm` + +When the active context is `cloud-stack`, `--organization` defaults to the +context organization. `cloud_stacks`, `stack`, and `stacks` are deprecated +aliases for `cloud stacks`, except `stack proxy`, which remains a deprecated +alias for the data-plane `target proxy` command. + +`cloud stacks create` prompts for missing name, region, and version in +interactive terminals. Region versions are sorted in descending semantic-version +order. Unless `--no-wait` is passed, create waits for stack availability before +printing the final styled success block. + +## Ledger + +- `fctl ledger create [name]` +- `fctl ledger list` +- `fctl ledger info` +- `fctl ledger stats` +- `fctl ledger import --file |-` +- `fctl ledger export --ledger ` +- `fctl ledger set-metadata [key=value]... --metadata-file |- --confirm` +- `fctl ledger delete-metadata --confirm` +- `fctl ledger accounts list` +- `fctl ledger accounts show ` +- `fctl ledger accounts query --schema-version ` +- `fctl ledger accounts set-metadata [key=value]... --metadata-file |- --confirm` +- `fctl ledger accounts delete-metadata --confirm` +- `fctl ledger schemas list` +- `fctl ledger schemas show ` +- `fctl ledger schemas insert ` +- `fctl ledger transactions list` +- `fctl ledger transactions show ` +- `fctl ledger transactions send` +- `fctl ledger transactions run-script --file |-` +- `fctl ledger transactions revert ` +- `fctl ledger transactions count` +- `fctl ledger transactions set-metadata [key=value]... --metadata-file |- --confirm` +- `fctl ledger transactions delete-metadata --confirm` +- `fctl ledger volumes list` + +Ledger commands use service-qualified internal names and adapt canonical CLI +flags to the selected Ledger API version. + +## Payments + +- `fctl payments versions` +- `fctl payments connectors install --file |-` +- `fctl payments connectors list` +- `fctl payments connectors config show ` +- `fctl payments connectors config update --file |-` +- `fctl payments connectors uninstall --confirm` +- `fctl payments accounts create --file |-` +- `fctl payments accounts list` +- `fctl payments accounts show ` +- `fctl payments accounts balances ` +- `fctl payments bank-accounts create --file |-` +- `fctl payments bank-accounts list` +- `fctl payments bank-accounts show ` +- `fctl payments bank-accounts forward ` +- `fctl payments bank-accounts set-metadata ... --confirm` +- `fctl payments payments create --file |-` +- `fctl payments payments list` +- `fctl payments payments show ` +- `fctl payments payments set-metadata ... --confirm` +- `fctl payments pools create --file |-` +- `fctl payments pools list` +- `fctl payments pools show ` +- `fctl payments pools delete --confirm` +- `fctl payments pools add-account ` +- `fctl payments pools remove-account --confirm` +- `fctl payments pools update-query --file |- --confirm` +- `fctl payments pools balances --at