Skip to content

feat(cli): Happy Tummy and pickio CLI findings — login, repo target, env create, env rule for writes, files/taxonomy/publish/delete - #77

Open
Domantas wants to merge 19 commits into
mainfrom
fix/happy-tummy-cli-findings
Open

Domantas wants to merge 19 commits into
mainfrom
fix/happy-tummy-cli-findings

Conversation

@Domantas

@Domantas Domantas commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

CLI findings from the Happy Tummy integration (N2, N3, N4, N5, N6, N9, N10, N11, N15) and two pickio items (N-21, N-11). Each finding was checked against origin/main = v1.31.0 first; all nine Happy Tummy items were still present there. One commit per finding (plus small follow-ups).

# Fix
N2 login: the device-token poll starts right after the code is printed; ENTER only opens the browser; the prompt is aborted when the poll ends
N3 ai init writes .norbix/project.json (host, projectId, env; no secrets) and names them in CLAUDE.md / AGENTS.md / the skill. Every command in the repo reads it after flags/NORBIX_* and before the profile. Its host acts like --host, so a [default] profile for another host and its key are not used there
N4 Notice on stderr when a newer CLI is on npm. It is cached in ~/.norbix/update-check.json and refreshed at most daily by a detached child (3 s timeout). It shows at most once a day, and always on login / ai init / whoami. Turn it off with NORBIX_NO_UPDATE_CHECK=1; NO_UPDATE_NOTIFIER and CI also turn it off
N5 env create <NAME> --connection-string-env VAR [--database-name] or --managed [--db-region]. Calls the existing environments.create. The secret is never on argv or in a dry run
N6 files commands use the env's defaultIntegrationId. With no files integration at all: exit 5 NO_FILES_INTEGRATION. With integrations but no default in this env: exit 2 with a list. The project-wide list is never used to pick one
N9 db taxonomy create <name>
N10 Every term command takes the taxonomy id (txn_…) or its name, and looks up the other key when the route needs it. A dry run sends no lookup
N11 db schema publish sends confirmed: false first. Only CM-ERRORS-SCHEMA-020 (fields removed) needs confirmation, then it resends with confirmed: true. --yes publishes in one call
N15 db delete --filter without --many deletes exactly one record: it reads at most 2 matches first; 0 matches → exit 5, 2 or more → exit 2 (add --many)
pickio N-21 A change never goes to PROD by default. This is the same rule as the MCP tools' AiToolEnvPolicy; see the table in the README
pickio N-11 Help and docs: "one Fake integration per environment", not "per project"
N7, N20 users import <file.json|csv> [--apply], users repair-roles [--apply], users repair-logins [--apply] for the new admin Hub routes. They check by default and --apply follows the env rule. They go through BaseCommand.hubRequest until the SDK has typed methods

Breaking: a command that changes data with no environment named (no --env, no NORBIX_ENV, and no saved non-PROD env in .norbix/project.json, the profile or env use) now exits 2 ENV_REQUIRED instead of writing to PROD. A profile whose saved env is PROD also exits 2 (PROD_NOT_EXPLICIT). Scripts that write to PROD must add --env PROD or NORBIX_ENV=PROD. Reads, dry runs and account/project-wide settings are unchanged.

Merge order: this branch is rebased onto feat/ai-context (c7cf498). Merge that PR first; until then this PR also shows its commit.

Tests: 968 → 1050 after the rebase, 40 files (1039 without ai-context's tests). npm test (build + vitest) is green.

🤖 Generated with Claude Code

Comment thread src/lib/update-check.ts Fixed
Domantas and others added 19 commits October 14, 2026 13:12
…orbix-ai/ after login and token renewal

`norbix ai context` prints the Hub's AI project-context summary
(GET /{v}/account/ai/context): every project the identity may work on —
environments, regions, modules, integrations with their default per env,
CORS origins, languages — scoped to its roles, never a secret. Markdown by
default, --json for the structured summary with its version, --project to
narrow, --write to save .norbix-ai/context.md + context.json (+ a .gitignore).

In a folder set up by `norbix ai init`, `norbix login` writes the copy and a
token renewal refreshes an existing one when its version changed (one
request with knownVersion). Both are silent and never fail the command; no
request at all in any other folder. The ai init block and skill tell the
agent to read the file and re-run the command after its context was
compressed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…pe hatch (N9)

Happy Tummy needed taxonomies before their schemas and had to call
`norbix hub database saveDatabaseTaxonomy`. The new command sends
saveDatabaseTaxonomy without a viewId (create, never replace), with
--description, --terms-meta-schema / --terms-ui-schema files, --parent and
repeatable --dependency, and --dry-run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`db term create txn_…` worked, then `db terms txn_…` answered 404 —
the gateway routes reads by taxonomy name and single-term writes by
taxonomy id. The id (txn_…) is the gateway's canonical key; the CLI now
accepts either in db taxonomy, terms, term, term tree/create/update/delete
and looks up the other with one read (getDatabaseTaxonomies /
getDatabaseTaxonomy). Only a txn_ value is an id (the gateway accepts no
other form), so there is no ambiguity. An unknown name exits 5
TAXONOMY_NOT_FOUND listing the taxonomies; a dry run sends no lookup and
shows a placeholder. New BaseCommand.lookup() for such pre-call reads.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`files list` without --integration failed with "No files integration ID"
even where the project has a default one. Every files command now
resolves --integration / NORBIX_FILES_INTEGRATION_ID / the profile, then
the Hub's defaultIntegrationId for the environment (else the only one).
None is its own error (exit 5 NO_FILES_INTEGRATION, naming the env);
several without a default exit 2 and list them. A dry run sends no
lookup.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`db delete --filter '{"_id":…}'` without --many was a usage error. The
safe default: --filter alone first reads at most two matches; exactly one
is deleted by its id (after the usual confirmation / --yes), none exits
5, and more than one is refused with exit 2 and a hint to add --many —
so a filter meant for one record can never delete several. --many and
--all are unchanged; an empty filter is still refused; a dry run sends
nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nge (N11)

`db schema publish` on a brand-new collection needed --yes like a
destructive command (exit 3 in scripts). The Hub already has the rule:
publish with confirmed: false goes through unless the new version
removes fields, then it answers CM-ERRORS-SCHEMA-020 with the removed
fields. The CLI now sends confirmed: false first; only on 020 does it
name the fields and confirm (prompt, or exit 3 without --yes), then
resends with confirmed: true. --yes up front still publishes in one
call. The command keeps --yes, so `norbix schema` still marks it
destructive (it can be).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d (N5)

Creating TEST needed `norbix hub environments create` and knowing that
the Hub requires a database integration. `env create <NAME>` sends
environments.create with the integration the gateway's converter
expects: --connection-string-env VAR (the MongoDB connection string is
read from that variable, never argv; a dry run shows $VAR, never the
secret) with optional --database-name, or --managed [--db-region] for a
Norbix-managed database. The name rule (A-Z, 0-9, space, <= 15, not
PROD) is checked before sending. Help and the env topic say what a new
environment needs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Happy Tummy ran 1.23.1 while 1.27.0 existed and nothing said so. The
init hook now prints one stderr line (never --json stdout) when the
cached latest version is newer: at most once a day, always on login,
ai init and whoami. It never waits: the version comes from
~/.norbix/update-check.json, refreshed at most daily by a detached,
unref'd child that asks the npm registry with a 3 s timeout. Off with
NORBIX_NO_UPDATE_CHECK=1, NO_UPDATE_NOTIFIER or CI, and for a 0.x
development build. The test setup switches it off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… (N3)

After `ai init` neither the skill nor CLAUDE.md named the host or the
project, and commands without --host used the computer's [default]
profile of another installation; the suggested `config set host`
would break that one. ai init now writes .norbix/project.json (host,
projectId, env — no secrets) from what the CLI resolves, and the agent
files name them. Every command in the repo (any sub-folder) reads it
after flags/NORBIX_* and before the profile; its host acts like --host,
so a [default] profile for another host (and its key) is not used. An
explicit --profile for another host wins. env use inside the repo
writes the file; whoami shows hostSource/envSource 'project file'. The
home folder is never searched; NORBIX_PROJECT_CONFIG=0 turns it off;
--no-project-file skips writing it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With no --env, no profile env and no sign-in env the CLI sent no
norbix-env header, and the gateway ran the call in PROD (MapOrProd).
Writes now follow the MCP surface's AiToolEnvPolicy: a change (every
command with --dry-run, every non-read hub/api call, raw with a method
other than GET) needs a named environment. --env / NORBIX_ENV (PROD
included) or a saved non-PROD default (.norbix/project.json, profile,
env use) is sent; no environment is refused with exit 2 ENV_REQUIRED,
PROD only from a saved default with exit 2 PROD_NOT_EXPLICIT; at a
terminal the CLI asks instead. --yes does not answer it; --dry-run is
never refused. Reads keep the server default. Account/project-wide
settings (account, project, module, env, AI service users) and the
integration test commands are not affected. whoami, --env help, the
README, docs/agent-contract.md and the ai init agent files say so.

Breaking: scripts that change data without naming an environment now
exit 2 instead of writing to PROD. Add --env PROD (or NORBIX_ENV=PROD)
to keep writing to PROD, or --env TEST.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t (pickio N-11)

The gateway allows one Fake per project AND environment
(Email.Integrations.cs), so PROD (seeded by module enable) and TEST
can each have one. The help of email/sms integration save and
docs/email.md, docs/sms.md said "one Fake per project".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`norbix login` printed the link and waited at "Press ENTER to open the
browser" before it started polling, so a person who opened the printed
link and pressed Allow stayed signed out until they pressed Enter. The
device-token poll now starts right after the code is printed; ENTER
only opens the browser, and the prompt is aborted (AbortSignal) as soon
as the poll ends — approved, denied or expired — so the CLI never waits
for a key that is no longer needed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…from the list (N6)

The Hub resolves defaultIntegrationId for the environment of the call
(Hub.Files/Integrations/GetAll.cs), but its integration list is
project-wide and its items carry no environment
(FetchFilesIntegrationsQuery.cs), so "the only one in the list" may be
another environment's. Without a default the command now stops (exit 2)
and lists the integrations instead of picking one; with none at all it
exits 5 NO_FILES_INTEGRATION.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he env rule (pickio N-21)

hub/api calls whose verb is aggregate, distinct, execute(Aggregate),
analyze, has, inspect, query, read, wait or run only read, but the env
rule for changes treated them as writes and refused them without --env.
They are read verbs now; a test runs distinct and aggregate with no
environment.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… trial (N5)

The gateway's EnvironmentCreationPolicy blocks a norbix.ai
managed-service trial; a self-hosted install with a licence is not on
trial, and the Happy Tummy client (self-hosted) has a TEST environment.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The planned path was built with path.join, so Windows reported
.norbix\project.json while every other agent file uses /.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CodeQL js/incomplete-sanitization: replace('/') changes only the first
one. The name has one, so the URL was right, but replaceAll says what
is meant.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Friendly commands for the new admin Hub routes on the gateway
(POST /membership/users/import, /repair-roles, /repair-logins). They
check or count by default (dryRun: true) and write only with --apply,
which follows the env rule for changes (a named environment; PROD only
with --env PROD). users import reads JSON (array or {users}) or CSV
(roles split on ";", profile columns into userGeneralInfo), sends
requests of 1000 users, continues row numbers across them and prints
the per-row table; --dry-run masks hashes and salts.

@norbix.ai/ts 4.26.0 has no typed methods for these routes yet, so
they go through the new BaseCommand.hubRequest (SDK headers, refreshed
session, gateway refusals as the error envelope). Switch them to the
typed SDK calls after the next SDK release.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…3 + ai context)

With feat/ai-context's project-context bullet and the N3 repo-target
bullet the CLAUDE.md / AGENTS.md block grew to 13 lines; the block is
kept at 12. The target sentence now ends the intro line instead of
being a bullet of its own; the skill keeps it as its own paragraph.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Domantas
Domantas force-pushed the fix/happy-tummy-cli-findings branch from fa5fb4f to e415772 Compare October 14, 2026 10:45
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.

2 participants