AgentFn.Cli 0.1.0-rc.3

This is a prerelease version of AgentFn.Cli.
dotnet tool install --global AgentFn.Cli --version 0.1.0-rc.3
                    
This package contains a .NET tool you can call from the shell/command line.
dotnet new tool-manifest
                    
if you are setting up this repo
dotnet tool install --local AgentFn.Cli --version 0.1.0-rc.3
                    
This package contains a .NET tool you can call from the shell/command line.
#tool dotnet:?package=AgentFn.Cli&version=0.1.0-rc.3&prerelease
                    
nuke :add-package AgentFn.Cli --version 0.1.0-rc.3
                    

AgentFn CLI

For the shortest end-to-end product walkthrough, start with the minimum aha moment guide.

Install the 0.1.0-rc.3 release candidate from NuGet:

dotnet tool install --global AgentFn.Cli --version 0.1.0-rc.3

For a local source build, pack and install from the repository:

dotnet pack agentfn-cli/src/AgentFn.Cli/AgentFn.Cli.csproj
dotnet tool install --global --add-source agentfn-cli/src/AgentFn.Cli/bin/Release AgentFn.Cli --version 0.1.0-rc.3

Authentication

The CLI supports normal user identities and Credential Clients through complementary browser, device-code, non-interactive, profile, and stateless flows. The AgentFn host defaults to https://agentfn.io-vii.com; use --base-url, a profile, or AGENTFN_BASE_URL to target another deployment.

Credential Client management

The CLI mirrors the authenticated console's Credential Client management operations:

agentfn-cli clients list
agentfn-cli clients users
agentfn-cli clients create orders-service \
  --display-name "Orders Service" \
  --allowed-skill order-review \
  --allowed-scope skill:run \
  --private-jwks-out ./orders-service.private.jwks.json \
  --public-jwks-out ./orders-service.public.jwks.json
agentfn-cli clients update orders-service --disable
export CLIENT_MODEL_TOKEN='replace-me'
agentfn-cli clients provider-tokens set orders-service PROVIDER_ID \
  --token-env CLIENT_MODEL_TOKEN
agentfn-cli clients provider-tokens delete orders-service PROVIDER_ID
agentfn-cli clients delete orders-service

On clients create, omit --jwks-file to let AgentFn generate three RSA signing keys. Prefer --private-jwks-out FILE and optionally --public-jwks-out FILE: the CLI reserves new files before creating the Client, refuses to overwrite existing paths, and writes each raw JWKS with mode 0600 on Unix. Successful subprocess output then contains the private file path instead of the private keys. Without the private output option, the CLI prints the private JWKS and matching public JWKS exactly once; AgentFn persists only the public JWKS. Pass --jwks-file public-jwks.json to register your own public key instead. Update supports replacement Developers, allowed Skills, scopes, JWKS, and enabled state; use clients users to discover member User IDs. The creator is automatically the immutable Owner, so create and update have no Owner option. Either the Owner or a Developer must explicitly add each callable Skill. OAuth scopes and the allowed-Skill list are both enforced, including for public Skills.

clients provider-tokens set reads the plaintext only from the named environment variable and stores a separately encrypted model Token owned by that Credential Client. Listing a Client returns only Token metadata. An Owner or Developer may set or delete these Tokens. Tasks can still pass one-shot business SessionSecrets, which remain separate from the Provider credential. The Client's own Provider Token is required for model access, and AgentFn never falls back to an Owner or Developer's personal Token.

User-level control plane

The CLI manages only resources owned by or delegated to the current User. Platform-administrator Provider, model, Runner, and User operations remain available through the platform administration UI and their dedicated JSON-RPC operations; the CLI does not expose a platform-scope switch.

agentfn-cli account show
agentfn-cli tasks stats
agentfn-cli tasks stats --skill-id reimbursement-review

account show reads the server-side User identity and personal Provider Token metadata; it is different from auth status, which reports only the selected local CLI profile. Task statistics match the authenticated console aggregation and are grouped by Skill version.

Manage an owned Provider, its discovery Key, personal execution Token, discovery, and manual models:

agentfn-cli providers register \
  --name private-openai \
  --display-name 'Private OpenAI' \
  --provider-base-url https://api.openai.com/v1/
agentfn-cli providers update PROVIDER_ID --display-name 'Private OpenAI v2'

export OPENAI_DISCOVERY_KEY='replace-me'
agentfn-cli providers discovery-key set PROVIDER_ID --key-env OPENAI_DISCOVERY_KEY
agentfn-cli providers discover PROVIDER_ID
agentfn-cli providers discovery-key delete PROVIDER_ID

agentfn-cli providers tokens list
export OPENAI_EXECUTION_TOKEN='replace-me'
agentfn-cli providers tokens set PROVIDER_ID --token-env OPENAI_EXECUTION_TOKEN
agentfn-cli providers tokens delete PROVIDER_ID

agentfn-cli models create PROVIDER_ID openai/gpt-5 \
  --display-name 'GPT-5' \
  --alias reasoning
agentfn-cli models update PROVIDER_ID MODEL_ID --disable

providers register is the atomic onboarding command when the Provider, optional discovery Key, synchronized personal Token, and initial manual models should commit together. providers update and models update apply only explicitly supplied fields, preserving all other configuration. Provider Key and Token plaintext is accepted only through the named environment variable.

Manage Skills owned by or delegated to the current User:

agentfn-cli skills managed list --query reimbursement
agentfn-cli skills users --search alice
agentfn-cli skills members get reimbursement-review
agentfn-cli skills members set reimbursement-review \
  --developer-user-id USER_ID

agentfn-cli skills drafts save ./reimbursement-review
agentfn-cli skills versions list reimbursement-review --status draft
agentfn-cli skills versions publish VERSION_ID --expected-revision REVISION
agentfn-cli skills versions deprecate VERSION_ID \
  --expected-revision REVISION \
  --reason 'Superseded by 2.0.0'
agentfn-cli skills versions delete-draft VERSION_ID --expected-revision REVISION

The version list returns the concurrency REVISION required by publish, deprecate, and draft deletion. skills drafts save creates or replaces only the matching draft from the folder; use skills publish FOLDER for the existing save-and-publish shortcut. Omitting every --developer-user-id from skills members set clears the Developer list.

1. Interactive login

Normal users use the platform's SMS/browser login through OAuth Authorization Code + PKCE. Before opening the browser, the CLI binds a free 127.0.0.1 port and uses it in the callback URI. The listener is closed after code exchange and profile save:

agentfn-cli auth login
agentfn-cli auth status

Use --no-browser to print the authorization URL without launching it; the CLI still waits on its temporary loopback listener. The built-in Client accepts arbitrary ports only for HTTP callbacks using the exact /callback/ path on localhost, 127.0.0.1, or ::1. A successful user login saves the access token, refresh token, public Client ID, and scopes in the selected profile. Expired access tokens are refreshed automatically.

Skill publication and management additionally require the caller to be entitled to skill:write. Explicit --scope values replace the normal defaults, so a profile that both manages and runs Skills should log in with the complete set:

agentfn-cli auth login \
  --scope openid \
  --scope profile \
  --scope offline_access \
  --scope skill:read \
  --scope skill:write \
  --scope skill:run \
  --scope task:read \
  --scope model:read

To obtain an Initial Access Token for RFC 7591 OAuth Client registration, include client.register together with every AgentFn scope the new delegated client may receive. The CLI Client is allowed to request this protocol scope, but it is intentionally absent from the normal login defaults:

agentfn-cli auth login \
  --scope openid \
  --scope profile \
  --scope offline_access \
  --scope client.register \
  --scope skill:read \
  --scope skill:run \
  --scope task:read \
  --scope model:read

Use the resulting User access token as the Bearer Initial Access Token at /oauth2/register; see the repository README for the RFC 7591 request and RFC 7592 rotation rules.

Credential Clients authenticate only with private_key_jwt. Interactive login prompts for the Client ID, RSA private-key PEM path, and the kid published in the Client's JWKS:

agentfn-cli auth login \
  --identity client \
  --scope skill:read \
  --scope task:read

2. Device-code login

Use OAuth Device Authorization Flow when the CLI runs on a remote host, container, or terminal that cannot receive a browser callback. The CLI prints a short user code, optionally opens the platform verification page, and polls the token endpoint at the server-provided interval:

agentfn-cli auth login --device-code

On a host with no browser, suppress the launch attempt and open the printed URL on another device:

agentfn-cli auth login --device-code --no-browser --timeout 900

The platform registers this flow under the separate public agent-fn-cli-device Client so the existing Authorization Code + PKCE Client and its loopback policy remain unchanged. Both flows save the same user profile shape and refresh tokens, and both resolve to the same opaque AgentFn user subject. With --output subprocess, the URL and user code are written to standard error while the single final JSON envelope remains on standard output.

3. Non-interactive login

For a Credential Client, pass the assertion-key configuration explicitly. The CLI creates a fresh, two-minute RS256 assertion, validates it at the Token Endpoint, and saves only the private-key path and kid in the profile:

agentfn-cli auth login \
  --identity client \
  --client-id my-service \
  --client-private-key /run/secrets/my-service-key.pem \
  --client-key-id my-service-key-2026-08 \
  --scope skill:read \
  --scope skill:run \
  --scope task:read \
  --scope model:read

For automation that already brokers an Authorization Code callback, generate an authorization URL, PKCE verifier, state, and selected loopback redirect URI. Complete SMS login in another browser, validate the returned state, and exchange the returned code with the same redirect URI:

agentfn-cli auth authorize \
  --output subprocess

agentfn-cli auth login \
  --authorization-code "$AUTHORIZATION_CODE" \
  --code-verifier "$CODE_VERIFIER" \
  --redirect-uri "$REDIRECT_URI" \
  --output subprocess

auth authorize --output subprocess returns redirectUri; preserve that exact value with the PKCE verifier. auth login requires --redirect-uri when exchanging an externally obtained code so the token request cannot silently use a different random port.

An already issued user or client Bearer token can be saved non-interactively from a protected file or pipe without placing it in shell history or process arguments:

agentfn-cli auth login --token-stdin < /run/secrets/agentfn-access-token

--token remains available for compatibility, but --token-stdin is preferred. Private-key paths and key IDs are not secret, but the referenced PEM must remain readable only by the intended service account; prefer protected variables or a pre-provisioned configuration file in automation.

4. Configuration profiles

--config selects a JSON file and --profile selects one of its profiles. Their environment compatibility aliases are AGENTFN_CONFIG_FILE and AGENTFN_PROFILE. The default file is the current user's platform configuration directory under AgentFn/config.json.

{
  "version": 1,
  "currentProfile": "production",
  "profiles": {
    "production": {
      "baseUrl": "https://agentfn.io-vii.com",
      "authenticationType": "credential_client",
      "clientId": "my-service",
      "clientPrivateKeyPath": "/run/secrets/my-service-key.pem",
      "clientKeyId": "my-service-key-2026-08",
      "scopes": ["skill:read", "skill:run", "task:read", "model:read"]
    }
  }
}

On Unix, CLI writes replace the configuration file with mode 0600. The file can contain private-key paths and user access/refresh tokens, so it must be handled as a credential file. Use agentfn-cli auth logout --profile production to clear saved authentication while retaining the profile's host configuration.

5. Stateless commands

Read a Bearer token from redirected standard input after any business subcommand. --token-stdin is recursive and has the highest authentication precedence without exposing the token in process arguments:

agentfn-cli skills list --token-stdin < /run/secrets/agentfn-access-token

The compatible recursive --token option remains available when standard input cannot be used.

Explicit options override compatible AGENTFN_* environment variables, which override the selected profile. The older environment-only flow remains supported:

export AGENTFN_BASE_URL='https://agentfn.io-vii.com'
export AGENTFN_CLIENT_ID='my-service'
export AGENTFN_CLIENT_PRIVATE_KEY='/run/secrets/my-service-key.pem'
export AGENTFN_CLIENT_KEY_ID='my-service-key-2026-08'
export AGENTFN_SCOPES='skill:read skill:run task:read model:read model-provider:manage user-byok:manage runner:manage'

agentfn-cli skills list
agentfn-cli skills search 'audit suspicious reimbursement claims'
agentfn-cli providers list
export MODEL_PROVIDER_DISCOVERY_KEY='...'
agentfn-cli providers register --name local-openai --display-name 'Local OpenAI' \
  --provider-base-url https://models.example/v1 \
  --discovery-key-env MODEL_PROVIDER_DISCOVERY_KEY
agentfn-cli models list --provider-id 456
agentfn-cli runners register --name gpu-runner --tag gpu --tag region:cn
agentfn-cli tasks create \
  --skill review-reimbursement@1.0.0 \
  --model openai/gpt-5 \
  --reasoning-effort high \
  --extra-body '{"chat_template_kwargs":{"enable_thinking":true}}' \
  --tag gpu \
  --attachments ./reimbursement-materials \
  --input 'Review the attached reimbursement claim' \
  --wait

Task status/result and internal Runtime steps are separate reads:

agentfn-cli tasks get TASK_ID
agentfn-cli tasks steps TASK_ID --offset 0 --limit 2000

tasks list, tasks get, and tasks steps read only the current calling subject's own Tasks. An authenticated User inspects a managed Credential Client's read-only history through the separate Client management commands; every current Owner and Developer is authorized:

agentfn-cli clients tasks list CLIENT_ID
agentfn-cli clients tasks get CLIENT_ID TASK_ID
agentfn-cli clients tasks steps CLIENT_ID TASK_ID --offset 0 --limit 2000
agentfn-cli clients tasks stats CLIENT_ID

When tasks steps reports a next offset, pass it to the next invocation to continue the ordered trace.

Retry a Failed, Cancelled, or TimedOut Task before its fixed seven-day deadline; Succeeded and active Tasks are not eligible:

agentfn-cli tasks retry TASK_ID --wait --timeout 600

Retry keeps TASK_ID, appends the next Attempt, and makes tasks get return that Attempt's latest status/result. tasks steps includes attemptNumber. The deadline is seven days after original Task creation and is not extended by retry; retained business Secrets and Attachments are deleted when it expires.

Task creation accepts compact catalog references instead of internal database IDs. --skill uses NAME@VERSION, where NAME is a Skill slug or unique display name. --model uses PROVIDER/MODEL, where the Provider is a name or unique display name and the model is an upstream name, unique alias, or unique display name. The model portion may contain additional slashes.

--reasoning-effort VALUE applies a Provider-supported reasoning level to every model call. --extra-body JSON accepts a non-secret JSON object up to 64 KiB and adds each property directly to every model request body. AgentFn-controlled model, messages, streaming, tools, tool choice, response format, and reasoning-effort fields cannot be overridden. Retry reuses the original values from the encrypted retry payload.

--idempotency-key KEY accepts an opaque 1–200 character key with no surrounding whitespace or control characters. For the same authenticated subject, retries with the same key return the original Task ID and never start a second Runtime, even if the later request body differs. Use a new key when the intended operation changes.

--attachments FOLDER recursively packages the folder contents as the Task workspace while preserving relative paths. It excludes a root .git/ and .DS_Store files and rejects symbolic links. Use exactly one of --input and --input-file.

--tag TAG is repeatable. A Runner can acquire a Task only when its registered tags contain every Task tag. runners register, runners set-tags, runners enable, and runners disable always manage only the current User's Runners, even when the caller is a platform administrator. Shared platform Runners use separate platform JSON-RPC operations or the platform administration UI. User-owned Providers registered with providers register can execute only on a Runner owned by the same User. When --discovery-key-env ENVIRONMENT_VARIABLE is present, registration sends the discovery Key from that variable to the atomic RegisterModelProvider operation. The Provider, encrypted discovery Key, personal execution Token, and every --model either commit together or are all rolled back. Add --no-sync-personal-token to omit the personal Token; synchronization requires the user-byok:manage scope included in normal CLI login. The CLI never accepts or prints the discovery Key as a literal command-line value.

The default --output interactive mode renders tables and human-readable Task summaries. For another Agent or subprocess, use --output subprocess. This mode writes exactly one single-line JSON envelope to stdout, writes handled errors to the envelope instead of stderr, and preserves the process exit code:

{"schemaVersion":1,"ok":true,"command":"tasks cancel","exitCode":0,"data":{"taskId":"42","cancelled":true}}
{"schemaVersion":1,"ok":false,"command":"skills list","exitCode":64,"error":{"type":"usage","code":"invalid_arguments","message":"Command line validation failed.","details":{"messages":["..."]}}}

Completion scripts and the hidden completion callback intentionally remain raw text rather than JSON. Task-scoped secrets use --secret-env SLOT=ENVIRONMENT_VARIABLE; use --strict-secret-env when the value is at least eight characters, has no surrounding whitespace, and requires exact length-preserving Runtime redaction. The CLI never prints either value. It validates slot names, duplicate slots, count and size limits, and Strict value rules before submitting the Task. Task wait commands report only status or Attempt transitions on standard error; their final human or subprocess result remains on standard output.

Publish a Skill folder

skills publish accepts a directory directly. Keep runtime Skill files at the folder root and local publication metadata under .agentfn/:

my-skill/
├── .agentfn/
│   ├── .skillignore        # optional
│   ├── manifest.json
│   └── output-schema.json
├── demo/                   # optional authoring fixture
├── SKILL.md
├── agents/
├── references/
└── scripts/

Only SKILL.md is required in the runtime package; the other runtime directories are optional. The CLI always excludes .agentfn/, a root .git/, and .DS_Store files from the ZIP it uploads. It also rejects symbolic links so selecting one folder cannot silently package files outside it.

.agentfn/manifest.json contains publication metadata:

{
  "skillId": "my-skill",
  "version": "1.0.0",
  "name": "My Skill",
  "description": "What the Skill does.",
  "visibility": "public",
  "changeNotes": "Initial release."
}

skillId, version, name, and changeNotes are required. description defaults to an empty string and visibility defaults to public; the other accepted visibility is private. .agentfn/output-schema.json must contain the JSON Schema that constrains the Task result.

Optional .agentfn/.skillignore keeps demos and other authoring-only files beside the Skill without publishing them. It accepts one root-relative glob per line, # comments, *, ?, and **; directory rules exclude the complete subtree. Negation rules beginning with ! are intentionally unsupported, and the root SKILL.md cannot be excluded. For example:

# Task fixtures are uploaded separately with --attachments.
demo/
**/*.tmp

Publish from the repository root or any directory:

agentfn-cli skills publish ./my-skill

The command packages the folder, creates the matching Draft, and immediately publishes it. If a previous attempt left the same version as a Draft, rerunning updates that Draft with its current revision before publishing. Published and deprecated versions are immutable; increment the manifest's SemVer version and update changeNotes for a new release.

The checked-in skills/use-agentfn-cli folder is a complete, directly publishable example maintained with the CLI.

Tab completion

The CLI uses the same System.CommandLine command tree for parsing, help, validation, and completion candidates. Enable completion for the current shell session with one of:

# Bash
eval "$(agentfn-cli completion bash)"

# Zsh
eval "$(agentfn-cli completion zsh)"

# Fish
agentfn-cli completion fish | source

For PowerShell:

Invoke-Expression (agentfn-cli completion powershell | Out-String)

Add the matching command to the shell profile for persistent completion. The generated shim calls back into agentfn-cli __complete; commands, options, and constrained values therefore stay synchronized with CLI help automatically.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

Version Downloads Last Updated
0.1.0-rc.3 63 9/1/2026
0.1.0-rc.2 71 8/31/2026
0.1.0-rc.1 84 8/28/2026

Third v0.1 release candidate with separate User and managed Credential Client Task-history commands and authorization boundaries.