Skip to content

Let any model answer, and a key be enough - #26

Merged
peopleworks merged 1 commit into
mainfrom
feat/byo-ai-key
Aug 18, 2026
Merged

Let any model answer, and a key be enough#26
peopleworks merged 1 commit into
mainfrom
feat/byo-ai-key

Conversation

@peopleworks

Copy link
Copy Markdown
Owner

Closes #24.

What was wrong

Every AI feature reached PeopleWorks Copilot for its credentials — not for a key the user had configured, but for the model's key, fetched from an account. On a public MIT repo published to nuget.org, that meant no outside user could run any of them.

--enrich requires API credentials. Configure with: xaflogic config
ERROR: Copilot API token is required for AI generation.
Set COPILOT_API_TOKEN env var or use --copilot-token <token>

Both name only the service the reader has no account with, and neither says another option exists — because none did.

Now

One resolver shared by the CLI and the Description Annotator, taking the first route that is configured:

--api-key on the command line, wins over everything
OPENAI_API_KEY in the environment, no configuration at all
ANTHROPIC_API_KEY in the environment
xaflogic config a PeopleWorks Copilot account, unchanged

--ai-base-url reaches any OpenAI-compatible endpoint including a local one, and --ai-model names the model. Anthropic goes through the same client — it serves an OpenAI-compatible surface, so it costs a base URL and a default model rather than a second SDK.

Probed against the built binary:

$ xaflogic extract --enrich                                    # existing account, untouched
AI: PeopleWorks | GPT5 / gpt-5.4
  Enriched 2/2 controllers, 1 actions

$ OPENAI_API_KEY=sk-... xaflogic extract --enrich
AI: OPENAI_API_KEY / gpt-4o-mini

$ xaflogic extract --enrich --api-key sk-... --ai-base-url http://localhost:11434/v1 --ai-model qwen2.5-coder
AI: the key passed on the command line / qwen2.5-coder

And with nothing configured, through the annotator:

No AI provider is configured. Any one of these is enough:

  --api-key <key>      a key passed directly, with --ai-base-url for any
                       OpenAI-compatible endpoint, including a local one
  OPENAI_API_KEY       set in the environment
  ANTHROPIC_API_KEY    set in the environment
  xaflogic config      an existing PeopleWorks Copilot account

Two decisions worth stating

A key is never read from or written to the configuration file. The endpoint and the model name are ordinary settings; a key is a secret, and ~/.xaflogic/config.json is a file that gets copied between machines. The environment is where a secret belongs.

The three options are global and read once with a pre-parse, rather than threaded through each handler. SetHandler takes at most eight parameters and extract already spends six, so adding three would have forced four commands onto the InvocationContext pattern to carry a setting none of them decides.

Tests

AiClientResolverTests — each route on its own, the two precedence rules that make the flags meaningful rather than decorative, an endpoint and model override, an empty account not counting as a configured one, and the message naming all four routes.

The environment is read through an injected lookup rather than the process, so the order can be pinned without setting a variable the rest of the run would share.

345 tests, no warnings.

Every AI feature reached PeopleWorks Copilot for its credentials -- not for a
key the user had configured, but for the model's key, fetched from an account.
On a public MIT project that meant no outside user could run any of them.
`--enrich` refused without an API URL and token and told the reader to
configure credentials for a service they had never heard of; the Description
Annotator asked for COPILOT_API_TOKEN and offered nothing else.

One resolver now serves both, taking the first route that is configured:
`--api-key` on the command line, then OPENAI_API_KEY or ANTHROPIC_API_KEY in
the environment, then a PeopleWorks Copilot account. That account keeps working
untouched -- it is one option among several rather than the gate.

`--ai-base-url` reaches any OpenAI-compatible endpoint, including a local one,
and `--ai-model` names the model. Anthropic is reached through the same client,
since it serves an OpenAI-compatible surface, so it costs a base URL and a
default rather than a second SDK. Someone with none of the routes configured is
now told all four.

A key is never read from or written to the configuration file. The endpoint and
the model name are ordinary settings; a key is a secret, and that file lives in
a home directory that gets copied around.

The three options are global and read once with a pre-parse rather than
threaded through each handler: SetHandler takes at most eight parameters and
extract already spends six, so adding three would have forced four commands
onto the InvocationContext pattern to carry a setting none of them decides.

The environment is read through an injected lookup so the order of the routes
is tested without setting process-wide state the whole run would share.

345 tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@peopleworks
peopleworks merged commit f83528e into main Aug 18, 2026
6 checks passed
@peopleworks
peopleworks deleted the feat/byo-ai-key branch August 18, 2026 00:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AI features are gated on a PeopleWorks Copilot account, with no bring-your-own-key path

1 participant