Raw JSON report machine-readable
{
"data": {
"repo": {
"topics": [],
"is_fork": false,
"size_kb": 1886,
"has_wiki": true,
"homepage": null,
"languages": {
"CSS": 4229,
"HCL": 22484,
"HTML": 14447,
"Python": 1085771,
"Dockerfile": 2566,
"JavaScript": 81,
"TypeScript": 507245
},
"pushed_at": "2026-07-20T11:07:41Z",
"created_at": "2026-04-23T13:19:56Z",
"owner_type": "Organization",
"updated_at": "2026-07-21T15:23:27Z",
"description": "Open-source AI-native ERP. Accounting, inventory, analytics — all through chat.",
"is_archived": false,
"is_disabled": false,
"license_spdx": "Apache-2.0",
"default_branch": "master",
"license_spdx_raw": "Apache-2.0",
"primary_language": "Python",
"significant_languages": [
"Python",
"TypeScript"
]
},
"owner": {
"blog": "https://lambda.dev",
"name": "Lambda Automation Development",
"type": "Organization",
"login": "lambdadevelopment",
"company": null,
"location": null,
"followers": 1,
"avatar_url": "https://avatars.githubusercontent.com/u/175140732?v=4",
"created_at": "2024-07-09T15:52:35Z",
"is_verified": null,
"public_repos": 3,
"account_age_days": 742
},
"license": {
"state": "standard",
"spdx_id": "Apache-2.0",
"raw_spdx": "Apache-2.0",
"file_present": true,
"scorecard_found": true,
"profile_has_license": true
},
"activity": {
"releases": [
{
"tag": "v0.3.4",
"kind": "patch",
"published_at": "2026-07-17T13:24:50Z"
},
{
"tag": "v0.3.3",
"kind": "patch",
"published_at": "2026-07-17T12:15:01Z"
},
{
"tag": "v0.3.2",
"kind": "patch",
"published_at": "2026-07-17T11:58:37Z"
},
{
"tag": "v0.3.1",
"kind": "patch",
"published_at": "2026-07-17T11:03:16Z"
},
{
"tag": "v0.3.0",
"kind": "minor",
"published_at": "2026-07-16T10:28:05Z"
},
{
"tag": "v0.2.6",
"kind": "patch",
"published_at": "2026-07-16T09:14:02Z"
},
{
"tag": "v0.2.5",
"kind": "patch",
"published_at": "2026-07-15T20:47:57Z"
},
{
"tag": "v0.2.4",
"kind": "patch",
"published_at": "2026-07-15T20:32:15Z"
},
{
"tag": "v0.2.3",
"kind": "patch",
"published_at": "2026-07-15T18:05:05Z"
},
{
"tag": "v0.2.2",
"kind": "patch",
"published_at": "2026-07-15T17:09:27Z"
},
{
"tag": "v0.2.1",
"kind": "patch",
"published_at": "2026-07-15T16:35:53Z"
},
{
"tag": "v0.2.0",
"kind": "minor",
"published_at": "2026-07-15T16:11:56Z"
},
{
"tag": "v0.1.49",
"kind": "patch",
"published_at": "2026-07-14T17:32:00Z"
},
{
"tag": "v0.1.48",
"kind": "patch",
"published_at": "2026-07-14T17:29:29Z"
},
{
"tag": "v0.1.47",
"kind": "patch",
"published_at": "2026-07-14T15:42:57Z"
},
{
"tag": "v0.1.46",
"kind": "patch",
"published_at": "2026-07-14T15:37:20Z"
},
{
"tag": "v0.1.45",
"kind": "patch",
"published_at": "2026-07-14T14:30:59Z"
},
{
"tag": "v0.1.44",
"kind": "patch",
"published_at": "2026-07-14T13:41:19Z"
},
{
"tag": "v0.1.43",
"kind": "patch",
"published_at": "2026-07-14T10:23:05Z"
},
{
"tag": "v0.1.42",
"kind": "patch",
"published_at": "2026-07-14T10:00:23Z"
},
{
"tag": "v0.1.41",
"kind": "patch",
"published_at": "2026-07-14T09:56:52Z"
},
{
"tag": "v0.1.40",
"kind": "patch",
"published_at": "2026-07-14T09:53:40Z"
},
{
"tag": "v0.1.39",
"kind": "patch",
"published_at": "2026-07-14T09:32:02Z"
},
{
"tag": "v0.1.38",
"kind": "patch",
"published_at": "2026-07-13T09:20:19Z"
},
{
"tag": "v0.1.37",
"kind": "patch",
"published_at": "2026-07-10T20:45:43Z"
},
{
"tag": "v0.1.36",
"kind": "patch",
"published_at": "2026-07-10T17:14:53Z"
},
{
"tag": "v0.1.35",
"kind": "patch",
"published_at": "2026-07-01T17:58:22Z"
},
{
"tag": "v0.1.34",
"kind": "patch",
"published_at": "2026-07-01T16:48:45Z"
},
{
"tag": "v0.1.33",
"kind": "patch",
"published_at": "2026-07-01T16:21:11Z"
},
{
"tag": "v0.1.32",
"kind": "patch",
"published_at": "2026-07-01T16:10:51Z"
},
{
"tag": "v0.1.31",
"kind": "patch",
"published_at": "2026-06-25T13:37:33Z"
},
{
"tag": "v0.1.30",
"kind": "patch",
"published_at": "2026-06-24T15:36:45Z"
},
{
"tag": "v0.1.29",
"kind": "patch",
"published_at": "2026-06-24T15:13:16Z"
},
{
"tag": "v0.1.28",
"kind": "patch",
"published_at": "2026-06-24T14:15:22Z"
},
{
"tag": "v0.1.27",
"kind": "patch",
"published_at": "2026-06-24T09:34:51Z"
},
{
"tag": "v0.1.26",
"kind": "patch",
"published_at": "2026-06-24T08:58:01Z"
},
{
"tag": "v0.1.25",
"kind": "patch",
"published_at": "2026-06-23T21:31:19Z"
},
{
"tag": "v0.1.24",
"kind": "patch",
"published_at": "2026-06-22T07:47:31Z"
},
{
"tag": "v0.1.23",
"kind": "patch",
"published_at": "2026-06-20T17:25:02Z"
},
{
"tag": "v0.1.22",
"kind": "patch",
"published_at": "2026-06-20T17:12:51Z"
},
{
"tag": "v0.1.21",
"kind": "patch",
"published_at": "2026-06-20T16:19:16Z"
},
{
"tag": "v0.1.20",
"kind": "patch",
"published_at": "2026-06-19T11:49:03Z"
},
{
"tag": "v0.1.19",
"kind": "patch",
"published_at": "2026-06-17T17:55:00Z"
},
{
"tag": "v0.1.18",
"kind": "patch",
"published_at": "2026-06-05T11:10:33Z"
},
{
"tag": "v0.1.17",
"kind": "patch",
"published_at": "2026-06-05T08:51:23Z"
},
{
"tag": "v0.1.16",
"kind": "patch",
"published_at": "2026-06-05T08:33:38Z"
},
{
"tag": "v0.1.15",
"kind": "patch",
"published_at": "2026-06-04T22:41:22Z"
},
{
"tag": "v0.1.14",
"kind": "patch",
"published_at": "2026-06-04T18:09:14Z"
},
{
"tag": "v0.1.13",
"kind": "patch",
"published_at": "2026-06-04T17:02:12Z"
},
{
"tag": "v0.1.12",
"kind": "patch",
"published_at": "2026-06-04T13:13:10Z"
},
{
"tag": "v0.1.11",
"kind": "patch",
"published_at": "2026-06-04T12:34:40Z"
},
{
"tag": "v0.1.10",
"kind": "patch",
"published_at": "2026-06-04T09:45:15Z"
},
{
"tag": "v0.1.9",
"kind": "patch",
"published_at": "2026-06-04T07:57:20Z"
},
{
"tag": "v0.1.8",
"kind": "patch",
"published_at": "2026-06-03T22:31:14Z"
},
{
"tag": "v0.1.7",
"kind": "patch",
"published_at": "2026-06-03T17:51:03Z"
},
{
"tag": "v0.1.6",
"kind": "patch",
"published_at": "2026-06-03T17:33:47Z"
},
{
"tag": "v0.1.5",
"kind": "patch",
"published_at": "2026-06-03T16:33:13Z"
},
{
"tag": "v0.1.4",
"kind": "patch",
"published_at": "2026-06-03T15:22:18Z"
},
{
"tag": "v0.1.3",
"kind": "patch",
"published_at": "2026-06-03T14:47:29Z"
},
{
"tag": "v0.1.2",
"kind": "patch",
"published_at": "2026-05-26T21:48:10Z"
}
],
"recent_commits": [
{
"oid": "39068a6e52f556509734450d296da9a3e65cc4a2",
"body": null,
"is_bot": false,
"headline": "Update LICENSE",
"author_name": "Jonathan C. Frei",
"author_login": "jcfrei",
"committed_at": "2026-07-20T11:07:41Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b7b8c193fac0c45a886a7de62d17ed76ed49fbe3",
"body": "Deactivating the chat API in Settings now shows a confirmation dialog (enabling\nstays instant) that makes clear the API keys are preserved — the flag only gates\nthe API surface; keys keep working when it's re-enabled. Frontend-only\n(settings.tsx + en/de/fr).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "release 0.3.4: confirm dialog before deactivating the chat API",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-17T13:23:53Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "350101b033e3bf95085fa5678149521ebd1a7d38",
"body": "…ds from chat\n\nsearch_masters hides disabled records by default (good — don't book to retired\naccounts), but they were unreachable: no way to find a disabled account to\nre-enable it (catch-22) or answer \"what's disabled\". Adds an optional\ninclude_disabled flag (default false) applied to the no-query\n[…]\nuzzy paths, plus a prompt nudge to retry with it when an expected record isn't\nfound. Mirrors the existing list_masters include_disabled param.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "release 0.3.3: search_masters include_disabled — reach disabled recor…",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-17T12:14:04Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "8d90394b3bbb0ca018468bb43fe35c8a8b043796",
"body": "…ol flag updates; anti-fabrication prompt\n\n- JournalEntry._normalize_amounts back-fills base debit/credit <-> *_in_account_currency\n so a JE created with amounts only in the account-currency fields (the chat path)\n actually posts; on_submit rejects a JE that would post no non-zero GL lines.\n- _nor\n[…]\nmpt: confirm actions from the tool result before claiming success;\n no master rename exists; verify a field exists before saying it's missing.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "release 0.3.2: journal entries post from account-currency amounts; bo…",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-17T11:57:30Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "407f4b89aaccdb0640b9f76aa561e8a308ab6353",
"body": "search_masters no longer hard-caps at 20 results: the chat can pass an optional\n`limit` (omit for no cap), so listing accounts returns the whole chart of\naccounts instead of a silently-truncated 20. Applies to the no-query listing,\nsubstring match, and fuzzy fallback. Backend-only; frontend version bumped to\nkeep the shared version in lockstep. Rebased onto 0.3.0 (Apache relicense).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "release 0.3.1: uncap master search (LLM-set limit; omit = all)",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-17T11:02:05Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "aec917afd71ed995eed7ac639d673eaa0fc25dde",
"body": "First Apache-2.0-licensed release of both packages (lambda-erp on PyPI,\n@lambda-development/erp-core on npm). Adds frontend/LICENSE so the npm\ntarball ships a license file. Releases through 0.2.6 remain MIT.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "release 0.3.0: relicense from MIT to Apache License 2.0",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-07-16T10:27:08Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "20aee90659269f6e3f589775ed0256f68e589c97",
"body": "index.html was returned with no Cache-Control, so browsers heuristically\ncached the shell and a normal reload could load an old shell pointing at\nprevious-build asset URLs — requiring a hard-refresh. Serve it no-cache so\nthe shell always revalidates (304 when unchanged). Also serve the\ncontent-hashe\n[…]\n a 1y max-age so reloads skip asset\nrevalidation entirely — net fewer requests, not more. Bump 0.2.5 -> 0.2.6\n(both packages version together).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(web): stop serving a stale SPA shell on soft refresh",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-16T09:12:57Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "10fc84adf7c38a0b9aa1d0c2273d06768de804af",
"body": "0.2.4 fixed /account/tree, but the CoA page the GUI renders is the\n/reports/chart-of-accounts report, which still listed disabled accounts\n(shown as \"disabled\"). It now hides them by default too, with the same\nprune rule (balances still roll up over disabled descendants; a disabled\ngroup with an enabled descendant is kept). include_disabled=true shows them.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "release 0.2.5: hide disabled accounts in the Chart of Accounts report",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-15T20:47:04Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "3a316b6fa666f69a2a74aaf524d001cf0a9643c6",
"body": "/account/tree now omits disabled accounts by default (they already drop out\nof account pickers), so a retired account leaves the CoA view instead of\nlingering as clutter. A disabled group is still shown when it has an enabled\ndescendant, so an active account is never hidden behind a disabled parent.\ninclude_disabled=true shows them; each node now carries a disabled flag.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "release 0.2.4: hide disabled accounts in Chart of Accounts tree",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-15T20:31:10Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "cb50615c1a9ca61f992fff94091cd1c1b453cb66",
"body": "Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "release 0.2.3: German DATEV SKR03/SKR04 localization packs",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-15T18:04:00Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "9f39496b14ff5061e23b03607f2766792cfb6577",
"body": "First use of the country[.variant] pack axis: two Germany charts registered\nunder country=\"de\" — de.skr03 (process-ordered, the most common German SME\nchart, and the default for a bare \"de\") and de.skr04 (balance-sheet-ordered,\nDATEV's recommendation for new companies). Each is a curated ~70-account\n[…]\nUpdates the chat tool descriptions, CHANGELOG [Unreleased], README, and the\ncontributor doc (de_skr03/04 now the multi-variant worked example).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(setup): add German DATEV SKR03/SKR04 localization packs",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-15T17:47:11Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "90687f45c891e197efa1233f1f431d3aa8230f6f",
"body": "…at bold-heading fix\n\nCompany setup now converges toward the desired chart instead of refusing when\nthe company already exists:\n- Accounts: create only what's missing (skip existing by name, no PK failure);\n parents-then-children so a partial chart completes.\n- Defaults: fill only empty company def\n[…]\ntead of being mangled into a `*` bullet.\n\nCloses the guided-setup dead-end seen when a company pre-existed with stray\naccounts (chat 2527ebc9).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "release 0.2.2: idempotent company setup (converge, don't refuse) + ch…",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-15T17:08:12Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "2ae9ecd2c1f6d50879c18fc92b50a894e52087cd",
"body": "The markdown list detector matched any line starting with `*`, so a bold\nheading like `**Grundlage**` had its first star stripped and emitted as a `•`\nbullet, leaving `*Grundlage**` unrendered. Require whitespace after the list\nmarker (`- `, `* `, `• `) so `**bold**` (star-star, no space) falls through to\nnormal inline rendering. Real bullets are unaffected.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(chat): render bold lines instead of mis-parsing them as bullets",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-15T16:45:26Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "63cf4bb753f1315b06b483f43c48a3e153dc55cf",
"body": "… line breaks\n\n- Sector-profile overlay accounts are created in the localization pack's language\n (LocalizationPack.language). On the Swiss (German) chart they now read in German\n (Beratungserlöse, Aufwand für Fremdleistungen, …) via per-account i18n names;\n generic stays English. Engine remaps p\n[…]\n line breaks in the user's own message bubble (whitespace-pre-wrap).\n- Tests cover German overlay names + the services default resolving on CH.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "release 0.2.1: localize sector accounts + fix services default + chat…",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-15T16:31:58Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "1ee06eb0870848895ebd5b84edd19dc193a0044f",
"body": "Add lambda_erp/accounting/setup/ — a three-layer chart-of-accounts builder:\na universal account_type spine, pluggable localization packs keyed\ncountry[.variant] (registry + permanent generic fallback), and seven\njurisdiction-independent sector profiles that attach accounts to pack anchors,\nnever to \n[…]\nt_company_setup.py\n (self-contained) + docs/agents/company_setup.md.\n- Bundles the held API-keys grouped-by-owner UI change into this release.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "release 0.2.0: guided sector-aware company setup + Swiss pack",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-15T16:09:00Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "4d8baa56d05530b5d07c598351195fba9c2cf8fc",
"body": "Make the admin \"sees everyone's keys\" behavior legible on the API keys page\ninstead of a flat, ambiguous list:\n\n- Backend: list_api_keys LEFT JOINs \"User\" so each key carries owner_full_name\n + owner_email, plus an is_mine flag. Additive only — no fields removed, safe\n for a mixed-version window. \n[…]\nm (Badge, semantic tokens, ring-bordered lists,\n Button variants) instead of ad-hoc gray utility classes.\n\nNo version bump yet (release held).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(api-keys): group keys by owner + confirm dialog for others' keys",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-15T13:39:57Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "36c87d753606316273351b7848cf6febb0e77c56",
"body": "0.1.48's per-user keys named the column `user`, which is a reserved word\nin PostgreSQL — schema setup died with 'syntax error at or near \"user\"'\n(SQLite happily accepted it; the dual-backend CI suite caught it before\nany deploy). Renamed to `owner` in the DDL, migration 19, and every\nquery; the seri\n[…]\nield stays `user` so the frontend and API\nconsumers are unchanged. 0.1.48 was published but never deployable on\nPostgres — no data implications.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "release 0.1.49: rename Api Key column user -> owner (PG reserved word)",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-14T17:30:59Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "b43929a6293a4eb936a5ed33d086801cff8fb471",
"body": "Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "release: 0.1.48",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-14T17:28:28Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "7a2c43c56a2ef74e982636c27cdca472acc35f74",
"body": "v1 keys were org-global objects minted by admins with a free-standing\nrole and a synthetic identity (session_owner apikey:<id>) — whoever held\nthe token WAS the key, with no user attribution and, via a shared org\ntoken, interleaved chat sessions across people.\n\nv2 (clean break, decided 2026-07-14 — \n[…]\nd: same-user keys SHARE sessions (semantic flip), plus\n cross-user isolation, cap enforcement, and the delete flow via a\n second (viewer) user\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "auth: per-user API keys (self-service, live role cap, two-step delete)",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-14T17:28:06Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "793d99792b285a2a766d3893d72917f782312f46",
"body": "The 0.1.46 Master Data Deletion prompt section contained a literal\n{\"disabled\": 1} inside build_system_prompt's f-string — syntactically\nvalid (py_compile passes: \"disabled\" parses as an expression with \" 1\"\nas its format spec) but raising \"Space not allowed in string format\nspecifier\" on EVERY prom\n[…]\npush. Escaped to {{\"disabled\": 1}};\nverified by evaluating the extracted f-string (also proves no other\nunescaped braces exist in the template).\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "release 0.1.47: fix chat prompt f-string (0.1.46 broke every chat turn)",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-14T15:41:58Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "1655bfac3861bcf244462f3c7a1265ee8dc5affc",
"body": "Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "release: 0.1.46",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-14T15:36:19Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "780b58357ecf71304e728f2893b1b0be37eba95f",
"body": "The master form pre-filled default_currency with a hardcoded \"USD\"\n(company form) or left it blank (customer/supplier) — so a hasty save\ngave a CHF shop USD customers. A dedicated effect now fills an untouched\ncurrency field with the company base currency once it loads, without\nwiping other fields t\n[…]\ner already typed. The backend create path\n(chat/API) already inherited the company currency for customer/supplier\n— this aligns the GUI with it.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(gui): new-master currency defaults to the company base currency",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-14T15:11:02Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "fc3cb8352092a18fef026284eea7a5b8bbc87033",
"body": "… USD)\n\nDoctypes without a per-document currency column (Stock Entry, ...) store\ntheir values in the company BASE currency, but three render paths fell\nback to a hardcoded \"USD\" when row/form data had no currency field —\nstamping $ on CHF numbers (display-only; stored values were correct):\n\n- docume\n[…]\n KPIs, table cells, and chart tooltips\n\nStandard report pages (trial balance, GL, aging, ...) already bound\nuseBaseCurrency and were unaffected.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(gui): stop stamping $ on base-currency values (Stock Entry showed…",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-14T15:07:24Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "fb33cf6fb4261311bff2243ad838c7360e6a91b7",
"body": "The agent had no way to delete master records and, worse, justified the\ngap with an invented policy (\"records are retained for audit integrity\")\ngeneralized from the documents-lifecycle prompt rule — while the GUI's\nadmin delete route worked fine (live repro: CUST-007 refusal, manual GUI\ndeletion ne\n[…]\n now scopes \"no delete /\n audit integrity\" explicitly to DOCUMENTS with a new Master Data\n Deletion section describing the protected behavior.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "chat: delete_master tool + scope the no-delete rule to documents",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-14T14:59:10Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "ce9fa8a260e9cf4d70cbaf7b150c0135078f036f",
"body": "The Account table always had full tree machinery (parent_account,\nis_group, root_type) but the GUI never exposed it — accounts were only\nvisible through Trial Balance / GL reports and the chat agent.\n\n- GET /reports/chart-of-accounts: every account (groups + zero-balance\n included) with period bala\n[…]\nral Ledger pre-filtered to\n account + period (the GL page is URL-backed, so drill-down is free).\n- i18n en/de/fr (Kontenplan / Plan comptable).\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "release 0.1.45: Chart of Accounts page",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-14T14:29:51Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "f9cc2e23ebfc077cbe9bb416c48d91218f98d0b4",
"body": "…OM guidance\n\nStock UOM (and every other master-form select) silently rendered the\n\"Select...\" placeholder when the stored value wasn't in the hardcoded\noption list — which is every chat-created item (\"Stück\", \"Bottle\",\n\"Unit\"): the backend value existed but the GUI looked unset, inviting\nusers to o\n[…]\ns as users add units), nudging the agent\nto reuse exact spellings; create_master guidance points at it. A proper\nUOM master remains future work.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "release 0.1.44: show out-of-list select values in the GUI + dynamic U…",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-14T13:40:16Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "4aa7aea161f5e9101f860b0848a775c69fab76dc",
"body": "… versioning)\n\n- System prompt: sales-doc VAT contract — one \"On Net Total\" taxes[] row;\n account_head OPTIONAL on drafts. The agent previously burned its step\n budget hunting for a Tax Payable account that rate-only lines don't need\n (live repro: 7/8 iterations, then refused; QTN-0004's working \n[…]\nw carries `modified` so callers can tell a\n stale PDF from the current one (timestamped attachment names).\n- Hoist ORCHESTRATOR_MODEL constant.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "release 0.1.43: chat agent robustness (VAT guidance, cap wrap-up, doc…",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-14T10:22:10Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "f91139e53f300b99467c0e867e9bb5f3e2c94a4d",
"body": "Complete the terra pricing entry with the 5.6 family's cache-write rates\n(3.125 / 6.25 per 1M, short/long context). gpt-5.4 verified against the\nofficial tiering table (272K threshold).\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "release 0.1.42: gpt-5.6-terra cache-write pricing",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-14T09:59:32Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "81969b40db46ed77b3d61ca5b978fbd8d26895d7",
"body": "…nput)\n\nOfficial model page: requests exceeding 272K input tokens incur 2x input\nand 1.5x output charges — same structure as gpt-5.4. 0.1.39's flat entry\nunder-counted large-context calls.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "release 0.1.41: gpt-5.6-terra pricing is tiered (2x/1.5x above 272K i…",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-14T09:55:56Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "d8fdc0e360afa630bef36f263c955a1c62253eca",
"body": "0.1.39's terra switch broke every chat turn: gpt-5.6-terra 400s on\n/v1/chat/completions when function tools are present unless\nreasoning_effort=\"none\" — and the loop swallows LLM errors into an\non_event, so it surfaced as silent empty replies. Set the param;\nResponses-API migration (reasoning + tools) is follow-up.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "release 0.1.40: fix gpt-5.6-terra tool calls (reasoning_effort=none)",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-14T09:52:49Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "001ba4f4ab0aea786e3e2c9c87b833ff9c874833",
"body": "Carries the chat orchestrator switch gpt-5.4 -> gpt-5.6-terra (5b66e5b).\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "release: 0.1.39",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-14T09:30:25Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "5b66e5b21df4f9e94f20b3d27602204f4cc76db4",
"body": "Register gpt-5.6-terra in OPENAI_PRICING (flat $2.50/$0.25/$15, no 272K tier\nstep-up) so cost tracking is accurate rather than falling back to gpt-5.4's\ntiered rate. Same price at normal context, stronger agentic tool-use.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "chat: switch orchestrator model gpt-5.4 -> gpt-5.6-terra",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-14T09:03:03Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "cae9f1addcabdcca099375bbefe790aab9948aa2",
"body": "Point readers to lambda-erp-example next to the PyPI/npm badges — a minimal\ndeployment that consumes both packages via version pins, a template to start from.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "docs(readme): link the reference deployment (lambda-erp-example)",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-13T12:49:08Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "5c2eee9869117ac1ece1f9f3eebec8d7131fe7c9",
"body": "Remove the \"not yet production-ready … run your payroll\" disclaimer and soften\nthe remaining prototype language (tagline, storage row, Status section) to a\nconfident-but-honest tone. No functional change.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "docs(readme): drop the not-production-ready framing",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-13T10:14:39Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "1f757918b713186752a9377c4cd480df85e8ebfb",
"body": null,
"is_bot": false,
"headline": "Release v0.1.38",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-13T09:17:05Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "cb069b2d0a8dc63907807ff39ee4ae70c0c5570c",
"body": "The chat agent writes for its own web UI, so API-channel replies contained\nERP-relative links (/app, /masters, /api/documents) that are dead outside the\nERP. Fix in two layers:\n\n- run_session_turn takes a `channel` (\"web\" | \"api\"); the API surface passes\n \"api\", switching the system prompt's link g\n[…]\ne-parsing prose.\n\nTests assert the api-channel prompt is applied and the documents array is\npopulated from a referenced PDF link. Docs updated.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(chat-api): channel-aware replies + structured document refs",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-13T09:13:34Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "fcc138ad69fed038e95602c37d943b56e4ed0f74",
"body": "Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "Document read endpoints on the chat API + self-host Inter — 0.1.37",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-10T20:44:38Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "cca56dd40e64d921ed04a210ddc79d151cc57cc7",
"body": "Chat replies link to /api/documents/{slug}/{name}/pdf, but that route is\ncookie-gated (require_role) and unreachable by a Bearer API caller — so PDFs a\nreply references can't be opened downstream (the iOS app / websocket).\n\nMirror them on the programmatic surface:\n- GET /api/v1/documents/{doctype_sl\n[…]\nerits the chat_api_enabled flag + key role). Missing\ndoc -> 404, unknown doctype -> 422 via the existing global handlers. Tests +\ndocs updated.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(chat-api): Bearer-gated document PDF + JSON read endpoints",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-10T20:40:41Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "b1332d09be4c4dd53177de1d7b56b79c2e6911ac",
"body": "The package's Tailwind preset sets fontFamily.sans to [\"Inter\", ...], but Inter\nwas only loaded by the demo's Google Fonts <link> in index.html — which is not\npart of the published @lambda-development/erp-core package. Consumers (e.g.\nlambda-erp-internal) therefore asked for \"Inter\" but loaded nothi\n[…]\ntop of src/index.css, which ships via exports[\"./styles.css\"]. Every\nconsumer of the stylesheet now gets Inter self-hosted, no <link> required.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(frontend): self-host Inter so consumers inherit the font",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-10T18:04:02Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "410c35c2f36abc6492b011977af2ecb2022c58f8",
"body": "npm@latest shipped 12.0.0, whose global self-upgrade left 'sigstore'\nunresolved and crashed provenance generation, failing the 0.1.36 npm\npublish (PyPI succeeded). Pin npm@11 and make the PyPI step skip-existing\nso re-pointing the v0.1.36 tag completes the release without choking on\nthe already-published PyPI version.",
"is_bot": false,
"headline": "ci(release): pin npm to 11.x + skip-existing on PyPI",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-10T17:11:18Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "84ac63b8199c78f06956d4559eaf4f842b9051a5",
"body": "Add a synchronous REST surface over the chat agent so an external application can\nconverse with an ERP instance (the basis for driving it from Lambda's own infra\nand, later, a mobile app). Off by default via the `chat_api_enabled` Settings\nflag; an admin enables it and issues Bearer API keys.\n\n- New\n[…]\ni18n en/de/fr.\n- Tests: tests/test_chat_api.py (gating/auth/keys/sessions/stateless-vs-replay),\n wired into CI on SQLite + Postgres.\n- Docs: docs/chat-api.md (usage) + docs/chat-api-plan.md (design).",
"is_bot": false,
"headline": "Programmatic chat API — opt-in Bearer-key chat endpoint — 0.1.36",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-07-10T17:03:55Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "66ad0bc1cb905c022693166292ff54c69ddbe3fe",
"body": "A user created via Google/Apple has no password. Settings now shows a \"Set a\nPassword\" card (no current-password field) so they can add an email+password\nfallback if they lose provider access.\n\n- New POST /auth/set-password (authenticated; refuses if a real password already\n exists — use change-pas\n[…]\nnge Password so password users are\n unaffected. Auth context gains refreshUser() to flip the card after setting.\n- i18n en/de/fr.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Set a password for social-login-only accounts — 0.1.35",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-07-01T17:57:25Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "00b7f18d621e3f71de5c7745cc908939320c5c5f",
"body": "When registration is closed (not first-run, public signup off), the login page\nno longer shows the \"Register\" link that led to a dead-end signup form. Invite-\nonly instances now show sign-in only (password + configured social providers);\ninvited users still register via their invite link, completable with a password\nor by continuing with Google / Apple.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "No signup screen on invite-only instances — 0.1.34",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-07-01T16:47:41Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "2f0ee9266b1a4c839a4d960e6dfa4fc0e946f9c4",
"body": "The \"User OAuth Identity\" table added in 0.1.32 had a column named `user`,\nwhich is a reserved word in PostgreSQL, so CREATE TABLE failed at startup on\nPostgres deployments (SQLite accepts it, so it passed local testing). Rename\nthe column to `user_name` and update all references. Verified against the\nPostgreSQL validation suite (books balance) and the OAuth flow on Postgres.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Fix social-login table crash on PostgreSQL (reserved word) — 0.1.33",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-07-01T16:20:03Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "dcc163d4ef703207d9ef98d3b71ef17e8a46b702",
"body": "Add OAuth/OIDC social login layered on the existing password auth: once a\nprovider proves identity, the same lambda_erp_token JWT cookie is minted, so\neverything downstream is unchanged and password login keeps working.\n\n- api/oauth.py: /auth/{provider}/login + /auth/{provider}/callback for Google\n \n[…]\n (buttons hidden).\n- Also: read-only Notes / Terms now preserve line breaks (whitespace-pre-line).\n\nSee docs/social-login-plan.md.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Social login (Google & Apple) + read-only notes line-break fix — 0.1.32",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-07-01T16:09:29Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "6bbbf3ccc306c1c769a53cbdb093e6d85543923c",
"body": "A submitted (read-only) document showed the Notes / Terms text in a <p>, which\ncollapses newlines. Render textarea fields with whitespace-pre-line in the\nread-only path so multi-line notes keep their formatting, matching the editable\ntextarea and the PDF.\n\nNo version bump — rides the next release.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Preserve line breaks in read-only Notes / Terms",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-06-29T16:59:59Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "d85d86be7c40da69e2b61b7b034650d31be5d5c1",
"body": "… 0.1.31\n\n- `---` (3+ dashes) in the Notes / Terms markup renders a full-width thin\n divider. Core emits a semantic `<div class=\"rm-hr\">`; templates style it\n (light grey default; a branded template can match its own separators).\n Documented in the chat system prompt and the formatting-help toolt\n[…]\nription -> posted invoices (Phase 0/1/2, scheduler via Container Apps\n Job, manual + chat conversion). No code from the plan yet.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Notes markup: horizontal rule (---), + recurring-subscriptions plan —…",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-06-25T13:36:33Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "a98e5cec19c6037480563af18c9e84a84e22f29a",
"body": "….1.30\n\n- Fix: the line-item search picker was clipped by the table's overflow-x-auto\n scroller. It now renders in a body portal with fixed positioning and follows\n the input on scroll/resize.\n- Docs: the chat system prompt now covers the quotation line `frequency`\n field (and when to use it vs the cosmetic `>>` note), and states the\n `>> left | amount` pipe rule explicitly.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Portal the link-field dropdown + document frequency/notes in chat — 0…",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-06-24T15:35:48Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "e0d7e9eb0ecdd9b28a6db58f6fbe4068a3be31d7",
"body": "A quotation line carries a frequency: One-time (default) or a recurring\ncadence (Monthly/Quarterly/Half-Yearly/Yearly, matching the Subscription\nintervals). When an offer mixes one-time and recurring lines, the headline\ntotals AND tax rows reflect the one-time part only, and each recurring\ncadence i\n[…]\ncker on\nquotation line items, and a split_by_frequency helper that runs the shared\ntax engine per group (engine itself unchanged).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Billing frequency on quotation lines (recurring offers) — 0.1.29",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-06-24T15:12:18Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "542d8d1ec0996391bab6dfd0ac2c0fb9a2d82e19",
"body": "The line-item table gains a Description column, so a quotation/order/invoice\nline can carry its own blurb (like a Proposal position). It defaults from\nthe Item master on save (blank falls back to the master, never wiping it);\na typed value overrides it for that document only. Backend already stored\nand defaulted the field — this exposes it in the form.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Editable per-line description on document line items — 0.1.28",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-06-24T14:14:21Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "4f7151b1bbfc966eac66f8548eaf9bb1fb19ce71",
"body": "The remarks field moves onto its own full-width row below the other\ndocument fields and is taller, with an info icon beside the label that\nexplains the supported markup (# heading, *italic*/**bold**, and the\nright-aligned `>> Period | Amount` price line) on hover or click.\nTranslated for en/de/fr.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Make the Notes / Terms field prominent + markup help — 0.1.27",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-06-24T09:33:54Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "124879fc8262c719331aee4fc04ad274956da91f",
"body": "The remarks field now renders on the PDF from a small markup subset\n(# headings, *italic*/**bold**, and a right-aligned `>> Period | Amount`\nprice line that sits beside the description above it), so a closing block\nreads like a real offer. generate_pdf exposes it as safe `remarks_html`;\ntemplates re\n[…]\nses, so a\nbranded template can restyle the same markup. The chat assistant knows\nthe syntax and uses it for customer-facing notes.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Lightweight markup for document Notes / Terms — 0.1.26",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-06-24T08:57:06Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "da8b2a9c5cfeb9ce9b8eb8e0dc9aa09d31a76fc5",
"body": "When unsure where a value belongs on a master, the assistant now consults\nget_master_fields before create_master/update_master (tool + system-prompt\nguidance; the ignored-fields warning points there too). create_master also\nspells out the customer contact-person mapping with an example. Fixes contact\npersons being dropped / contact phones misfiled into the company phone.\n\nNo version bump — rides the next release.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "Chat: discover master fields instead of guessing",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-06-23T22:06:58Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "7f1638f84338bd44a640271681cbf0993041f795",
"body": "Master search: case-insensitive matching (fixes a Postgres-only bug where\nsearch returned nothing unless the exact stored casing was typed), searches all\ntext columns incl. address/city, fuzzy-matches misspellings, with an optional\n`fields` arg to target columns and a new get_master_fields tool.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "Bump to lambda-erp 0.1.25",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-06-23T21:30:25Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "5979ac8c1d16608eb7e5d88d993819ef90ac542b",
"body": "…ix, addressing your three follow-ups.\n\n 1. Per-column targeting (fields)\n\n search_masters now accepts an optional fields list. When provided it searches only those columns (validated against the\n real schema; unknown names → clear error). It uses lower(CAST(col AS TEXT)) so even non-text columns\n[…]\nty + ERP validation suites pass locally on SQLite; the Postgres leg (where the original case bug lived) runs in\n CI.\n\n Still unpushed — say the word and I'll branch and open a PR against lambda-erp.",
"is_bot": false,
"headline": "All green on both suites. Here's what I added on top of the earlier f…",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-06-23T21:10:20Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "eb3ad3a69f69f02cbfcbc7fb20ccd7ad7bd4819e",
"body": "The custom Proposal page had no way to remove a proposal. Add a Discard button\n(existing proposals only, with a confirm) that soft-deletes via the standard\ndiscard_document path (status Discarded, hidden from the list).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Add Discard action to the Proposal builder — 0.1.24",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-06-22T07:46:26Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "bd232036f78cb87fc24822a0c78db3b609bab6cb",
"body": "…— 0.1.23\n\nThe 0.1.22 Proposal guidance embedded a `{...}` JSON example in build_system_prompt's\nf-string, so the braces were treated as format fields and every chat message\nraised \"Invalid format specifier\". Rephrase the example as brace-free prose and\nadd the German doctype names (Sammelofferte/Sammelofferten) so the assistant\nmaps them to proposals.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Fix chat crash: literal braces in the Proposal system-prompt section …",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-06-20T17:24:06Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "42126b26cfe61943bf4c9900fd88a7c06bef461a",
"body": "Add `proposal` to the LLM document tools (create/read/update/list) and\ndocument its shape in the system prompt: the quotations[] child table\nreferences existing quotations (not items), and it is print-only. Guard the\nProposal class against submit so an accidental submit raises a clear error.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Expose Proposal (Sammelofferte) to the chat assistant — 0.1.22",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-06-20T17:11:54Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "f85da195b332033875029c5b0d851659f594d660",
"body": "A print-only document that assembles several independent quotations into one\nbranded PDF: each rendered as a lettered position (A, B, C…) with an optional\nrecommendation badge, a cover letter pre-filled from a per-company template,\nand an optional uploaded appendix PDF stapled on the end (pypdf). No\n[…]\nthe nav. Tables Proposal / Proposal Item / Proposal Appendix\n(appendix as a blob); Company.proposal_cover_template (migration 17).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Add Proposal (Sammelofferte) — combine quotations into one PDF — 0.1.21",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-06-20T16:18:15Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "3ff8f3fc0b041a435cc91c31007b4515291917bf",
"body": "The Customer master gains contact_person / contact_email / contact_phone\n(a named contact at the customer, distinct from the company-level\nemail/phone). Surfaced in the master form with en/de/fr labels and in the\nchat create_master/update_master tools. Additive migration 16; existing\ncustomers keep the fields empty until edited.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Add contact person (Ansprechperson) to Customer master — 0.1.20",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-06-19T11:47:55Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "7950677ceba3084adf6d04d60ec906bc4efc5033",
"body": "A microphone button in the chat composer records a spoken message,\ntranscribes it with OpenAI gpt-4o-transcribe, and drops the text into the\ninput for review before sending (it does not auto-send). Click to start,\nclick to stop; a too-short accidental tap is ignored without an API call.\n\n- api/chat.\n[…]\n_of_transcription().\n- frontend: mic button + MediaRecorder capture in the composer, transcribeAudio\n on the chat context, and de/en/fr labels.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "Release v0.1.19: voice-to-text in chat",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-06-17T17:52:57Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "6c63ecd736e773a5c725c73286958203abeba48f",
"body": "Added — Discard draft:\n- Document.discard() soft-deletes an unwanted DRAFT (discarded=1, status\n 'Discarded'): keeps the row for the audit trail, hides it from default lists,\n no GL/stock impact. Drafts only; submitted docs must be cancelled. submit()\n refuses a discarded draft (no \"posted but hi\n[…]\ninline confirmation\n(confirm button placed apart from the original) so a double-click can't fire an\nirreversible posting reversal.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Release v0.1.18: discard draft (void) + two-step cancel confirmation",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-06-05T11:09:24Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "a423566e54ba2c4a000b6cf6640174e6ad8c24d9",
"body": "…tings UI\n\nFixed:\n- Change Password form now works with password managers: autocomplete\n current-password / new-password (on both new + confirm so managers fill the\n generated password into both), unique id/name per field, and a hidden\n username anchor (autocomplete=username, display:none) so 1Pa\n[…]\nnding-invite \"Copy link\" / \"Revoke\" are now proper Buttons\n (secondary / danger) instead of text links, matching \"Create Invite\".\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Release v0.1.17: password-manager-friendly change-password form + set…",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-06-05T08:50:28Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "47e1be2c6ae2fa7922b8ff053599e4e7cd45f693",
"body": "Signed-in users can change their own password from General Settings (a card\nreachable by every role; hidden for the shared public_manager demo account).\n\nNew endpoint POST /auth/change-password verifies the current password, requires\nthe new one to be >= 6 chars, and rejects public_manager. Wrong current -> 403,\ntoo short -> 422. Auth-flow regression (both backends) extended to cover it.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Release v0.1.16: change password",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-06-05T08:32:39Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "613ae2885586aa916ec5f2972b38a6e2b0029a13",
"body": ".lambda-logo-icon masked its gradient with url('/logo_lad_erp.png') — an\nabsolute path to an asset only in the core's own public/ and not shipped in the\nnpm package, so every downstream deployment (e.g. acme-erp, lambda-erp-internal)\nrendered a broken/empty logo. Move the mark to src/logo_lad_erp.pn\n[…]\ne files. The Paint.NET source moves to frontend/design/ so it stops\nshipping in builds. Frontend only; backend bumps for lockstep.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Release v0.1.15 (fix sidebar logo for consumer deployments)",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-06-04T22:40:31Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "8d7535085e74fdec503105f17a1afde10096a7b7",
"body": "… fix\n\nAdded:\n- Opt-in public signup. New admin setting `allow_public_signup` (default off)\n under General Settings; when on, anyone may self-register as a viewer. First\n user still bootstraps as admin; toggle off keeps registration invite-only.\n setup-status now returns first_run / public_signup\n[…]\n admin-only, leads with total LLM spend off-demo.\n- Double-quoted-literal CI guard now scans continuation lines of multi-line SQL.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Release v0.1.14: opt-in public signup, invite management, Token Spend…",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-06-04T18:08:05Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "218a0a89d2a359635864246279f0223d2d220925",
"body": "Two generic mechanisms a deployment plugin needs to render a payment slip\n(e.g. a Swiss QR-bill) without forking the core:\n\n- register_pdf_context(fn): providers fn(doctype, name, context) return extra\n keys merged into the PDF render context just before rendering. Exceptions in\n a provider are sw\n[…]\nn field (schema + migration _m014) and an IBAN input on the\n company master form. generate_pdf now includes iban in company_info.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Release v0.1.13: register_pdf_context seam + Company.iban",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-06-04T17:00:39Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "12afba01448497e515ea90213cbd85260f266150",
"body": "…url)\n\ngenerate_pdf sets WeasyPrint base_url to the rendered template's directory, so\na register_pdf_template_dir override can `<img src=\"logo.png\">` a logo (or load\nfonts/CSS) sitting next to its document.html.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Release v0.1.12 (PDF templates can reference sibling assets via base_…",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-06-04T13:12:11Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "9d80c0f4c5cf72186a8fbb05caf7bf5d4e4e63cd",
"body": "- register_pdf_template_dir: deployments can override the invoice/document PDF\n template with their own styling.\n- New customers/suppliers inherit the company's base currency instead of\n defaulting to USD (fixes non-USD companies getting USD-defaulted documents);\n Currency field exposed on the master forms.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Release v0.1.11 (PDF template seam + party currency inheritance)",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-06-04T12:33:44Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "7d48aee25f7e4ac0f46bb0d406f3f51d443509ee",
"body": "Deployment plugins can register a template directory whose document.html (and\nother templates) override the built-in invoice/document PDF, searched before\nthe core's via a Jinja ChoiceLoader. Custom templates get the same render\ncontext generate_pdf() builds, so they only restyle the same data. No change\nwhen nothing is registered.\n\nNo release cut (per request); lands on master in [Unreleased].\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Add PDF template override seam (register_pdf_template_dir)",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-06-04T12:28:34Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "16a00976167701278c4d1c4c0f15ada3f206c53c",
"body": "New customers/suppliers defaulted to USD (the default_currency column default),\nso a non-USD company (e.g. CHF) got USD customers that forced sales/purchase\ndocuments to USD and failed with no USD->base rate. create_master_record now\nfills default_currency from the company when not provided (explici\n[…]\n it\nwas only settable via the API/chat, hence invisible in the UI.\n\nNo release cut (per request); lands on master in [Unreleased].\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Party masters inherit company currency; expose Currency on the form",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-06-04T12:18:29Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "0d238d71cfb10a5d552480784ea85b4527491db7",
"body": "The v0.1.10 release failed because pypa/gh-action-pypi-publish is a Docker\naction whose image is pulled from ghcr.io, and the anonymous pull returned\n\"docker: ... unauthorized\" (ghcr anonymous-pull rate limit / flake) — the\npublish never reached PyPI. Log in with GITHUB_TOKEN first so it's an\nauthenticated pull. Adds packages: read.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "ci(release): authenticate to ghcr.io before the PyPI publish step",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-06-04T09:42:57Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "502d41f375b9642e44d721bb01556c69f6616909",
"body": "…fill)\n\n/setup/company used to fill missing contact fields with a deterministic\npseudo-random US address (for complete-looking demo PDFs) — so every real\ncompany got a bogus address on its invoices. The setup form now collects\naddress/city/zip/country/tax-id/email/phone (optional), and the backend only\nauto-fills when the caller passes autofill_address (the demo seeding does).\nReal setups keep unprovided fields blank.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Release v0.1.10 (Company Setup: collect real address, stop fake auto-…",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-06-04T08:44:29Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "f0501f137840b7798dbb2a37eeec23b36b28bb16",
"body": "A NavLink to a path that's a prefix of a sibling's (/setup \"Company Setup\" vs\n/setup/opening-balances \"Opening Balances\") matched active on the longer path's\npage, so both rows showed the active grey background on the Opening Balances\npage. Items nested under a sibling now use exact (end) matching. Frontend-only;\n0.1.9 for lockstep.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Release v0.1.9 (sidebar: stop double-highlighting nested nav paths)",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-06-04T07:56:25Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "703018c0363f7bf89b48c2a265dfb8716627cbea",
"body": "…mplete)\n\nFrontend-only changes; backend bumps for version lockstep.\n\n- Setup page gains a \"Create empty company, no demo data\" seed mode that creates\n only the company + chart of accounts and seeds nothing.\n- Sidebar hides the \"Company Setup\" (/setup) link once a company exists.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Release v0.1.8 (Company Setup: no-data option + hide nav link once co…",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-06-03T22:30:17Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "e50b3695b25a5494d045a8a5dce9ce593231eb84",
"body": "Two frontend-only changes to the Company Setup flow, both for all deployments:\n\n- setup page gains a third seed mode, \"Create empty company, no demo data\",\n that creates only the company + chart of accounts and seeds nothing (for real\n deployments starting from scratch). Backend already exposed co\n[…]\nxisting setup-status\n query invalidation makes the link vanish reactively. Getting Started and\n Opening Balances are unaffected.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Setup: add no-data option + hide Company Setup nav link once complete",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-06-03T22:29:16Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "9bceb63a7dfd63d9680672e9fdbeb3bb40780ec8",
"body": "db.sql() always called fetchall(); after INSERT/UPDATE/DELETE psycopg raises\n\"the last operation didn't produce records\" (SQLite returns []). This broke the\nchat/WebSocket path (constant disconnect/reconnect) and other db.sql write call\nsites. Now fetches only when cursor.description is not None. test_db_portability\nextended to assert write-via-db.sql() returns [] on both backends. Frontend\nunchanged; 0.1.7 for lockstep.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Release v0.1.7 (db.sql() no longer raises on Postgres for writes)",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-06-03T17:50:07Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "d71064d07e881c4816d1ac7200958e2c59d656d3",
"body": "…esilience)\n\nDouble-quoted string literals in SQL (WHERE x = \"value\", IN (\"a\",\"b\")) broke on\nPostgres — it reads \"...\" as an identifier, not a string — 500ing auth/chat/pdf\n/master paths. Converted all to single-quoted values. Also: a failed statement\nunder autocommit=False left the thread-local con\n[…]\ny (static double-quote scan + functional auth\nsmoke test on both backends), wired into CI. Frontend unchanged; 0.1.6 for lockstep.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Release v0.1.6 (fix double-quoted SQL literals; Postgres connection r…",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-06-03T17:32:50Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "24ef54e0572c541f11fe621927a7e8b83d00fd1a",
"body": "gotchas.md gains the dual-backend portability rules (portable SQL, the\ntransaction-abort and quoted-identifier differences); decisions.md updates the\nSQLite-vs-Postgres entry to reflect optional Postgres (added because Azure SMB\ncan't host SQLite's file locks).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "docs(agents): note dual SQLite/Postgres backend",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-06-03T16:54:41Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "4e3895c8b0ab2c31617a670c0461f649588f58d9",
"body": "Add a Postgres backend to lambda_erp/database.py alongside SQLite (still the\ndefault). Select it at runtime via LAMBDA_ERP_DB=postgresql://...; install the\ndriver with the new lambda-erp[postgres] extra. A _PgConn wrapper (?->%s) and\n_PgRow (mirrors sqlite3.Row) keep the ~35 internal + external db.c\n[…]\nn SQLite AND a Postgres service container;\nboth produce identical balanced books. Frontend unchanged; ships at 0.1.5 for\nlockstep.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Release v0.1.5 (optional PostgreSQL backend)",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-06-03T16:32:10Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "ed2e388ef47b30eac5c213f1bb44823f0795c1d4",
"body": "…yments)\n\nWAL needs a memory-mapped -shm file, so `PRAGMA journal_mode=WAL` fails with\n\"database is locked\" when the SQLite DB lives on an SMB/NFS share (e.g. Azure\nFiles). Add LAMBDA_ERP_SQLITE_JOURNAL_MODE (default WAL, allowlist-validated);\na network-FS deployment sets it to DELETE. Frontend unchanged; ships at 0.1.4\nto keep the packages in lockstep.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Release v0.1.4 (configurable SQLite journal mode for network-FS deplo…",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-06-03T15:21:11Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "806e1abe145b2acdbc93632960cde5d73fa33d26",
"body": "Add version badges for lambda-erp (PyPI) and @lambda-development/erp-core\n(npm) to the top badge cluster — standard for published packages and the\nlinks were missing.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "docs: link PyPI + npm package pages from README",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-06-03T14:54:57Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "6c258904bac97f68544444e83b9d42fa1110ba12",
"body": "…buildable)\n\nerp-core@0.1.2 emitted an absolute /assets/report-runtime.worker-*.js URL\nfrom `new Worker(new URL(...))`, which a downstream Vite build resolved\nagainst its own public/ dir and failed on (\"Could not resolve entry\nmodule\"). Import the worker with ?worker&inline so it's embedded as a blo\n[…]\nindex.js — nothing external for consumers to resolve. Backend\nunchanged; ships at 0.1.3 only to keep the two packages in lockstep.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Release v0.1.3 (fix: inline analytics worker so erp-core is consumer-…",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-06-03T14:45:57Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "d3acdc5e375360ef86b55001c9921c4beb319999",
"body": null,
"is_bot": false,
"headline": "some updates to readmes",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-06-02T14:00:35Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "7ee15a557616e0633273a2f090f86a33cbcb1138",
"body": " - Backend lambda-erp and frontend @lambda-development/erp-core are both published and live on PyPI + npm at 0.1.2, via a keyless OIDC tag-triggered pipeline (release.yml) that also auto-creates the GitHub Release from the changelog.\n - The doc now records Phase C as DONE with the three hard-won l\n[…]\nt README-only (it doesn't prove the packages compose), and a separate project (rather than an examples/ dir, which tends to drift to workspace deps and clutter the monorepo) — which is what you chose.",
"is_bot": false,
"headline": "What's done (Phases A → C)",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-05-26T22:22:50Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "dc7cda947f1031085fd1179c181831f46b77a9d5",
"body": " - actions/checkout@v4 → @v5 (×4)\n - actions/setup-python@v5 → @v6\n - actions/setup-node@v4 → @v6\n\n (pypa/gh-action-pypi-publish@release/v1 isn't in the list because it's a Docker-based action, not a Node one — it doesn't trigger this warning.)\n\n These take effect on the next release run, since\n[…]\n bump it to checkout@v5 too if you want to clear that warning as well. Want me to?\n\n Sources:\n - Deprecation of Node 20 on GitHub Actions runners\n - actions/setup-node (v6)\n - actions/setup-python",
"is_bot": false,
"headline": "Done — release.yml updated and YAML re-validated:",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-05-26T21:51:01Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "9283e56386bb7120a27b83b61446d3b1bf8b5856",
"body": null,
"is_bot": false,
"headline": "Release v0.1.2 (fix npm provenance: add repository to package.json)",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-05-26T21:47:03Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "60a3c6c0e6b3887c246ab2f82b9af3ffc677b286",
"body": null,
"is_bot": false,
"headline": "Release v0.1.1",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-05-26T21:41:00Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "098d9051d8cebbafc040d85e2657c02ad5fb13e7",
"body": "…e packaging plan.",
"is_bot": false,
"headline": "Done — docs/releasing.md is the runbook, with a pointer added from th…",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-05-26T21:31:55Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1468730436fa4242ad6b9770b3e5458e64ee1ac6",
"body": " 1. CHANGELOG.md (root) — Keep-a-Changelog + SemVer, one unified log for both packages, seeded with the 0.1.0 entry (core engine, multi-currency, stock analytics, i18n, open-core packaging) and an empty [Unreleased] to accrue into. Notes that the\n extension seams are the semver-governed surface.\n \n[…]\nrs the Azure deploy (code changes), so tell me whether to commit + push or just commit and hold —\n and then the first keyless release is: bump both to 0.1.1, git tag v0.1.1 && git push origin v0.1.1.",
"is_bot": false,
"headline": " What I added",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-05-26T21:25:21Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "19fb1af25272357e9a5d2cbf809343a23d9a3ff9",
"body": " What I just did\n\n .github/workflows/release.yml (new) — tag-v*-triggered (+ manual dispatch), fully keyless OIDC:\n - verify-version — fails the release unless tag (minus v) == pyproject version == frontend/package.json version. Dry-ran the extraction: both read 0.1.0. ✓\n - publish-pypi — python\n[…]\necisions (OIDC, release env, private flipped) and the remaining manual checklist.\n\n Validated: release.yml parses as YAML, package.json is valid JSON with private gone, version-lockstep check passes.",
"is_bot": false,
"headline": " Phase C's code is in place and validated.",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-05-26T20:50:49Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "0a111ae896f08ce1e6492722202238f49be5d999",
"body": "… re-verified.\n\n What I changed and confirmed:\n - Renamed @lambda/erp-core → @lambda-development/erp-core across frontend/package.json, src/index.ts, vite.lib.config.ts, tailwind.preset.ts, the README customer-deployment section, and both planning docs. No\n stale references remain.\n - Regenerate\n[…]\n and the trusted-publisher settings to paste into each\n registry.\n - Sequencing footer marks 1–3 done, Phase C next. Also synced docs/core-extension-architecture.md and the README to the final name.",
"is_bot": false,
"headline": "Done — the package is now @lambda-development/erp-core everywhere and…",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-05-26T18:12:51Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "b52908c28e90248d0f4f7be0c1a8f0a98e1e4a6f",
"body": " Frontend override seams (additive — demo app unchanged, builds green):\n - Doctype registry — registerDoctype on the existing lib/doctypes.ts (pages already read it live).\n - Route registry — routes.tsx now exposes registerRoute + buildRoutes() with merge-by-path, so a registered route overrides \n[…]\nk → a scratch consumer app installed the tarball + peers and tsc --noEmit passed while\n exercising every seam. Docker's npm ci stays valid (lockfile regenerated). README + both planning docs updated.",
"is_bot": false,
"headline": "Phase B is done and verified. Here's what landed.",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-05-26T17:46:50Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "e00e5cdabc43d676a10be799d7678053b8f3108d",
"body": " pyproject.toml\n - Build backend flit → hatchling. flit packages only the one module matching the project name, so it was silently dropping api — the wheel would've installed without register_doctype / load_plugins / the\n document classes. Now: packages = [\"lambda_erp\", \"api\"].\n - Added readme, \n[…]\np venv (kept dist/).\n\n One nice side effect: a future pip install -e . now makes api importable via the editable install itself, instead of only working because you launch uvicorn from the repo root.",
"is_bot": false,
"headline": "Phase A is done. Here's what changed and how it was verified.",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-05-26T17:16:10Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "0caf64e1d8751e68be5a2da434d1992ff8869975",
"body": " Added \"Building a customer deployment on top of the core\" to README.md (after \"Repository layout\"). It tells a future dev/LLM how to: stand up a separate private repo that depends on the core, override logic\n (subclass + register_doctype), add behavior (register_hook, with the before-=in-txn / af\n[…]\nis a no-op.\n Env + injected modules + hooks are restored in finally.\n\n So the whole extension seam — registry, hooks, converters, and the loader — is now regression-protected in the canonical suite.",
"is_bot": false,
"headline": "README",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-05-26T16:29:21Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "862dd8e0a8cf336e82ef49ca59ba6626aed4772a",
"body": " - register_converter(source, target, fn) — lets a plugin replace conversion logic for a (source, target) pair.\n - convert_document now honors class overrides generically: after the core converter builds the (base-class) target doc, if a subclass is registered for that doctype, it upgrades the ins\n[…]\n hook lifecycle events, swap converter logic, and is loaded via LAMBDA_ERP_PLUGINS — all without editing\n core files, all additive (zero impact when no plugin is set), and all exercised by the suite.",
"is_bot": false,
"headline": "What landed (api/services.py)",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-05-26T16:20:52Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "eda874862a40703089da8aa10ed0422e27795416",
"body": " api/main.py — new load_plugins(), called in the lifespan right after setup() (so overrides/hooks are registered before anything — including demo seeding — creates documents):\n - Reads LAMBDA_ERP_PLUGINS (comma-separated module names), imports each, and calls its register().\n - Fails fast if a na\n[…]\n(registered a hook + doctype path).\n - A module without register() raises a clear RuntimeError.\n - Empty LAMBDA_ERP_PLUGINS is a clean no-op.\n - api.main imports fine; full validation suite passes.",
"is_bot": false,
"headline": " What landed",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-05-26T16:15:59Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "bc27cb37315d6433117804c9283ee6dc6b69d2d1",
"body": " Phase 1 — registry seam (api/services.py)\n - Added register_doctype(doctype, cls, slug=None) over the existing DOCUMENT_CLASSES dict. Since get_document_class already resolves live, all of create/load/update/submit/cancel_document honor an override\n automatically — no other change needed.\n\n Pha\n[…]\nnd zero-impact by default: with no plugins registered, run_hooks is an empty dict lookup and the registry holds the core classes, so existing behavior is byte-identical (the full suite\n confirms it).",
"is_bot": false,
"headline": " What landed",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-05-26T16:02:10Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "1de26ea5ac8cbdd01f48ebddaa7939ed88208033",
"body": " - 167 label keys (fields.*, conversions.*, tables.*, tutorial.chips.*, tutorial.links.*) — the key suffix is the English label (and matched the inline defaultValue), so derived directly.\n - 40 step strings (tutorial.steps.N.{title,description,tip}) — recovered from the STEPS array that's still in\n[…]\ns at all), I can remove them as a follow-up; otherwise they're a safe belt-and-suspenders.\n\n en.json, de.json, and fr.json are now structurally identical, so future missing-key drift is easy to spot.",
"is_bot": false,
"headline": " What I moved into en.json (244 keys)",
"author_name": "Jonathan",
"author_login": "jcfrei",
"committed_at": "2026-05-26T10:51:30Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "15b3f81cf134424982caa684b9994f70670ea15c",
"body": " Dashboard — the four metric cards (Total Revenue, Outstanding Receivable/Payable, Total Stock Value), the \"Recent Documents\" heading, the empty state, and each recent-doc's doctype label.\n\n Chat — empty-state title + subtitle, the four suggestion chips, \"Load older messages\", attachment statuses \n[…]\ner your call. Everything's been verified green — want me to commit the whole i18n effort now (engine + reports + forms + lists + dashboard + chat + tutorial)? If so I'll\n group it into clean commits.",
"is_bot": false,
"headline": "What's now translated (en/de/fr)",
"author_name": "Jon",
"author_login": "jcfrei",
"committed_at": "2026-05-25T22:15:24Z",
"body_truncated": true,
"is_coding_agent": false
}
],
"releases_count": 60,
"commits_last_year": 148,
"latest_release_at": "2026-07-17T13:24:50Z",
"latest_release_tag": "v0.3.4",
"releases_from_tags": false,
"days_since_last_push": 2,
"active_weeks_last_year": 11,
"days_since_latest_release": 5,
"mean_days_between_releases": 0.2
},
"community": {
"has_readme": true,
"has_license": true,
"has_description": true,
"has_contributing": false,
"health_percentage": 50,
"has_issue_template": false,
"has_code_of_conduct": false,
"has_pull_request_template": false
},
"ecosystem": {
"packages": [
{
"name": "lambda-erp",
"exists": true,
"license": "Apache-2.0",
"keywords": [],
"ecosystem": "pypi",
"matches_repo": null,
"registry_url": "https://pypi.org/project/lambda-erp/",
"is_deprecated": false,
"latest_version": "0.3.4",
"repository_url": null,
"versions_count": 63,
"total_downloads": null,
"dependents_count": null,
"deprecation_note": null,
"maintainers_count": null,
"monthly_downloads": 4886,
"first_published_at": "2026-05-26T21:37:29.460244Z",
"latest_published_at": "2026-07-17T13:24:31.340288Z",
"latest_version_yanked": null,
"days_since_latest_publish": 5
},
{
"name": "@lambda-development/erp-core",
"exists": true,
"license": "Apache-2.0",
"keywords": [],
"ecosystem": "npm",
"matches_repo": true,
"registry_url": "https://www.npmjs.com/package/@lambda-development/erp-core",
"is_deprecated": false,
"latest_version": "0.3.4",
"repository_url": "https://github.com/lambdadevelopment/lambda-erp",
"versions_count": 61,
"total_downloads": null,
"dependents_count": null,
"deprecation_note": null,
"maintainers_count": 1,
"monthly_downloads": 6160,
"first_published_at": "2026-05-26T21:12:41.847000Z",
"latest_published_at": "2026-07-17T13:24:40.890000Z",
"latest_version_yanked": null,
"days_since_latest_publish": 5
}
]
},
"popularity": {
"forks": 5,
"stars": 20,
"watchers": 0,
"fork_history": {
"days": [
{
"date": "2026-05-26",
"count": 1
},
{
"date": "2026-06-17",
"count": 2
},
{
"date": "2026-06-28",
"count": 1
},
{
"date": "2026-07-14",
"count": 1
}
],
"complete": true,
"collected": 5,
"total_forks": 5
},
"star_history": null,
"open_issues_and_prs": 0
},
"ai_readiness": {
"has_nix": false,
"example_dirs": [],
"has_llms_txt": false,
"has_dockerfile": true,
"has_mcp_signal": false,
"bootstrap_files": [],
"api_schema_files": [],
"has_devcontainer": false,
"typecheck_configs": [
"frontend/tsconfig.json"
],
"toolchain_manifests": [],
"largest_source_bytes": 181453,
"source_files_sampled": 145,
"oversized_source_files": 3,
"agent_instruction_files": [
"CLAUDE.md"
],
"agent_instruction_max_bytes": 1598
},
"dependencies": {
"manifests": [
"frontend/package.json",
"pyproject.toml"
],
"advisories": {
"error": null,
"scope": null,
"source": null,
"findings": [],
"collected": false,
"malicious": [],
"truncated": false,
"by_severity": {},
"advisory_count": 0,
"affected_count": 0,
"assessed_count": 0,
"malicious_count": 0,
"assessed_package": null,
"unassessed_count": 0,
"direct_affected_count": 0
},
"ecosystems": [
"npm",
"pypi"
],
"dependencies": [
{
"name": "@fontsource/inter",
"manifest": "frontend/package.json",
"ecosystem": "npm",
"version_constraint": "^5.2.8"
},
{
"name": "fastapi",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=0.115"
},
{
"name": "uvicorn",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=0.30"
},
{
"name": "python-multipart",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=0.0.9"
},
{
"name": "pydantic",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=2.0"
},
{
"name": "anthropic",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=0.40"
},
{
"name": "openai",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=1.0"
},
{
"name": "httpx",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=0.27"
},
{
"name": "python-dotenv",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=1.0"
},
{
"name": "python-dateutil",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=2.8"
},
{
"name": "python-jose",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=3.3"
},
{
"name": "bcrypt",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=5"
},
{
"name": "Jinja2",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=3.1"
},
{
"name": "weasyprint",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=62.0"
},
{
"name": "pypdf",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=4.0"
},
{
"name": "holidays",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=0.40"
}
],
"all_dependencies": {
"error": "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
"source": null,
"packages": [],
"collected": false,
"truncated": false,
"total_count": null,
"direct_count": null,
"indirect_count": null
}
},
"maintainership": {
"issues": {
"open_prs": 0,
"merged_prs": 0,
"open_issues": 0,
"closed_ratio": null,
"closed_issues": 0,
"closed_unmerged_prs": 0
},
"bus_factor": 1,
"bot_contributors": 0,
"top_contributors": [
{
"type": "User",
"login": "jcfrei",
"commits": 148,
"avatar_url": "https://avatars.githubusercontent.com/u/523261?v=4"
}
],
"contributors_sampled": 1,
"top_contributor_share": 1
},
"quality_signals": {
"has_ci": true,
"has_tests": true,
"ci_workflows": [
"ci.yml",
"deploy.yml",
"release.yml",
"terraform-apply.yml"
],
"has_docs_dir": true,
"linter_configs": [],
"has_editorconfig": false,
"has_linter_config": false,
"has_precommit_config": false
},
"security_signals": {
"lockfiles": [
"package-lock.json"
],
"scorecard": {
"checks": [
{
"name": "Binary-Artifacts",
"score": 10,
"reason": "no binaries found in the repo",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
},
{
"name": "Branch-Protection",
"score": 0,
"reason": "branch protection not enabled on development/release branches",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
},
{
"name": "CI-Tests",
"score": null,
"reason": "no pull request found",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
},
{
"name": "CII-Best-Practices",
"score": 0,
"reason": "no effort to earn an OpenSSF best practices badge detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
},
{
"name": "Code-Review",
"score": 0,
"reason": "Found 0/30 approved changesets -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
},
{
"name": "Contributors",
"score": 3,
"reason": "project has 1 contributing companies or organizations -- score normalized to 3",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
},
{
"name": "Dangerous-Workflow",
"score": 10,
"reason": "no dangerous workflow patterns detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
},
{
"name": "Dependency-Update-Tool",
"score": 0,
"reason": "no update tool detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
},
{
"name": "Fuzzing",
"score": 0,
"reason": "project is not fuzzed",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
},
{
"name": "License",
"score": 10,
"reason": "license file detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
},
{
"name": "Maintained",
"score": 10,
"reason": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
},
{
"name": "Packaging",
"score": 10,
"reason": "packaging workflow detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
},
{
"name": "Pinned-Dependencies",
"score": 1,
"reason": "dependency not pinned by hash detected -- score normalized to 1",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
},
{
"name": "SAST",
"score": 0,
"reason": "no SAST tool detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
},
{
"name": "Security-Policy",
"score": 0,
"reason": "security policy file not detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
},
{
"name": "Signed-Releases",
"score": null,
"reason": "no releases found",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
},
{
"name": "Token-Permissions",
"score": 0,
"reason": "detected GitHub workflow tokens with excessive permissions",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
},
{
"name": "Vulnerabilities",
"score": 0,
"reason": "11 existing vulnerabilities detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
}
],
"commit": "39068a6e52f556509734450d296da9a3e65cc4a2",
"ran_at": "2026-07-22T15:11:10Z",
"aggregate_score": 3.6,
"scorecard_version": "v5.5.0"
},
"has_codeql_workflow": false,
"has_security_policy": false,
"has_dependabot_config": false
},
"contribution_flow": {
"collected": true,
"ci_last_run_at": null,
"oldest_open_prs": [],
"last_merged_pr_at": null,
"ci_last_conclusion": null,
"oldest_open_issues": []
}
},
"config": {
"disabled_metrics": [],
"disabled_categories": [],
"disabled_components": {}
},
"source": {
"url": "https://github.com/lambdadevelopment/lambda-erp",
"host": "github.com",
"name": "lambda-erp",
"owner": "lambdadevelopment"
},
"metrics": {
"overall": {
"key": "overall",
"band": "moderate",
"name": "Overall health",
"note": null,
"notes": [],
"value": 53,
"inputs": {
"security": 36,
"vitality": 83,
"community": 45,
"governance": 34,
"engineering": 66
},
"components": []
},
"categories": [
{
"key": "vitality",
"band": "good",
"name": "Vitality",
"value": 83,
"weight": 0.22,
"metrics": [
{
"key": "development_activity",
"band": "good",
"name": "Development activity",
"note": null,
"notes": [],
"value": 72,
"inputs": {
"commits_last_year": 148,
"human_commit_share": 1,
"days_since_last_push": 2,
"active_weeks_last_year": 11
},
"components": [
{
"key": "push_recency",
"name": "Push recency",
"detail": "last push 2 days ago",
"points": 36,
"status": "met",
"details": [
{
"code": "push_recency",
"params": {
"days": 2
}
}
],
"max_points": 36
},
{
"key": "commit_cadence",
"name": "Commit cadence",
"detail": "11/52 weeks with commits",
"points": 7.6,
"status": "partial",
"details": [
{
"code": "commit_cadence_weeks",
"params": {
"weeks": 11
}
}
],
"max_points": 36
},
{
"key": "commit_volume",
"name": "Commit volume",
"detail": "148 commits in the last year",
"points": 18,
"status": "met",
"details": [
{
"code": "commits_last_year",
"params": {
"count": 148
}
}
],
"max_points": 18
},
{
"key": "openssf_scorecard_maintained",
"name": "OpenSSF Scorecard: Maintained",
"detail": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
"points": 10,
"status": "met",
"details": [],
"max_points": 10
}
]
},
{
"key": "release_discipline",
"band": "excellent",
"name": "Release discipline",
"note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"openssf_scorecard_signed_releases"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 100,
"inputs": {
"releases_count": 60,
"latest_release_tag": "v0.3.4",
"releases_from_tags": false,
"days_since_latest_release": 5,
"mean_days_between_releases": 0.2
},
"components": [
{
"key": "ships_releases",
"name": "Ships releases",
"detail": "60 releases published",
"points": 27,
"status": "met",
"details": [
{
"code": "releases_published",
"params": {
"count": 60
}
}
],
"max_points": 27
},
{
"key": "release_recency",
"name": "Release recency",
"detail": "latest release 5 days ago",
"points": 36,
"status": "met",
"details": [
{
"code": "release_recency",
"params": {
"days": 5
}
}
],
"max_points": 36
},
{
"key": "release_cadence",
"name": "Release cadence",
"detail": "a release every ~0.2 days",
"points": 27,
"status": "met",
"details": [
{
"code": "release_cadence",
"params": {
"gap": 0.2
}
}
],
"max_points": 27
},
{
"key": "openssf_scorecard_signed_releases",
"name": "OpenSSF Scorecard: Signed-Releases",
"detail": "no releases found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 10
}
]
},
{
"key": "abandonment",
"band": "excellent",
"name": "Abandonment",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"cap": null,
"state": "unverified",
"guards": [],
"signals": [],
"red_flag": false,
"multiplier_pct": 100,
"declared_reason": null,
"unverified_reason": "repository_too_young",
"unanswered_open_prs": null,
"unanswered_open_issues": null,
"days_since_last_merged_pr": null,
"days_since_last_human_commit": null,
"days_since_last_human_commit_is_floor": false
},
"components": [
{
"key": "project_is_still_maintained",
"name": "Project is still maintained",
"detail": "maintenance record not established from the collected data",
"points": 100,
"status": "met",
"details": [
{
"code": "abandonment_unverified",
"params": {}
}
],
"max_points": 100
}
]
}
],
"description": "Is the project alive — is code being written and are releases shipping?"
},
{
"key": "community",
"band": "at_risk",
"name": "Community & Adoption",
"value": 45,
"weight": 0.18,
"metrics": [
{
"key": "popularity",
"band": "critical",
"name": "Popularity & adoption",
"note": null,
"notes": [],
"value": 26,
"inputs": {
"forks": 5,
"stars": 20,
"watchers": 0,
"growth_state": "unverified",
"growth_factor_pct": 100,
"growth_unverified_reason": "no_history"
},
"components": [
{
"key": "stars",
"name": "Stars",
"detail": "20 stars",
"points": 20.7,
"status": "partial",
"details": [
{
"code": "stars",
"params": {
"count": 20
}
}
],
"max_points": 60
},
{
"key": "forks",
"name": "Forks",
"detail": "5 forks",
"points": 5,
"status": "partial",
"details": [
{
"code": "forks",
"params": {
"count": 5
}
}
],
"max_points": 25
},
{
"key": "watchers",
"name": "Watchers",
"detail": "0 watchers",
"points": 0,
"status": "missed",
"details": [
{
"code": "watchers",
"params": {
"count": 0
}
}
],
"max_points": 15
}
]
},
{
"key": "community_health",
"band": "moderate",
"name": "Community health",
"note": null,
"notes": [],
"value": 50,
"inputs": {
"has_readme": true,
"has_license": true,
"has_contributing": false,
"has_issue_template": false,
"has_code_of_conduct": false,
"has_pull_request_template": false
},
"components": [
{
"key": "readme",
"name": "README",
"detail": null,
"points": 22.5,
"status": "met",
"details": [],
"max_points": 22.5
},
{
"key": "license",
"name": "License",
"detail": "recognized license (Apache-2.0)",
"points": 22.5,
"status": "met",
"details": [
{
"code": "license_standard",
"params": {}
},
{
"code": "license_spdx",
"params": {
"spdx": "Apache-2.0"
}
}
],
"max_points": 22.5
},
{
"key": "contributing_guide",
"name": "CONTRIBUTING guide",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 18
},
{
"key": "code_of_conduct",
"name": "Code of conduct",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 13.5
},
{
"key": "issue_template",
"name": "Issue template",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.2
},
{
"key": "pr_template",
"name": "PR template",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 6.3
}
]
},
{
"key": "ecosystem_adoption",
"band": "moderate",
"name": "Ecosystem adoption (downloads)",
"note": "Excluded from scoring (no data or not applicable): Registry dependents. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"registry_dependents"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 67,
"inputs": {
"packages": [
"lambda-erp",
"@lambda-development/erp-core"
],
"dependents": null,
"ecosystems": "npm, pypi",
"total_downloads": null,
"monthly_downloads": 11046
},
"components": [
{
"key": "monthly_downloads",
"name": "Monthly downloads",
"detail": "11,046 downloads/month across npm, pypi",
"points": 53.9,
"status": "partial",
"details": [
{
"code": "downloads_monthly",
"params": {
"count": 11046,
"ecosystems": "npm, pypi"
}
}
],
"max_points": 80
},
{
"key": "registry_dependents",
"name": "Registry dependents",
"detail": "not reported by this ecosystem",
"points": 0,
"status": "excluded",
"details": [
{
"code": "not_reported_by_this_ecosystem",
"params": {}
}
],
"max_points": 20
}
]
}
],
"description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
},
{
"key": "governance",
"band": "at_risk",
"name": "Sustainability & Governance",
"value": 34,
"weight": 0.24,
"metrics": [
{
"key": "maintainer_resilience",
"band": "critical",
"name": "Maintainer resilience (bus factor)",
"note": null,
"notes": [],
"value": 13,
"inputs": {
"bus_factor": 1,
"contributors_sampled": 1,
"top_contributor_share": 1
},
"components": [
{
"key": "bus_factor",
"name": "Bus factor",
"detail": "1 contributor(s) cover half of all commits",
"points": 9,
"status": "partial",
"details": [
{
"code": "bus_factor",
"params": {
"count": 1
}
}
],
"max_points": 54
},
{
"key": "commit_distribution",
"name": "Commit distribution",
"detail": "top contributor authored 100% of commits",
"points": 0,
"status": "missed",
"details": [
{
"code": "top_contributor_share",
"params": {
"share": 100
}
}
],
"max_points": 22.5
},
{
"key": "contributor_breadth",
"name": "Contributor breadth",
"detail": "1 contributors",
"points": 1.4,
"status": "partial",
"details": [
{
"code": "contributors_sampled",
"params": {
"count": 1
}
}
],
"max_points": 13.5
},
{
"key": "openssf_scorecard_contributors",
"name": "OpenSSF Scorecard: Contributors",
"detail": "project has 1 contributing companies or organizations -- score normalized to 3",
"points": 3,
"status": "partial",
"details": [],
"max_points": 10
}
]
},
{
"key": "responsiveness",
"band": "critical",
"name": "Issue & PR responsiveness",
"note": "Excluded from scoring (no data or not applicable): Issue resolution, PR acceptance. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"issue_resolution",
"pr_acceptance"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 1,
"inputs": {
"merged_prs": 0,
"open_issues": 0,
"closed_issues": 0,
"issue_closed_ratio": null,
"closed_unmerged_prs": 0
},
"components": [
{
"key": "issue_resolution",
"name": "Issue resolution",
"detail": "no issues or no data",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_issues_or_data",
"params": {}
}
],
"max_points": 46.75
},
{
"key": "pr_acceptance",
"name": "PR acceptance",
"detail": "no decided pull requests or no data",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_decided_prs_or_data",
"params": {}
}
],
"max_points": 38.25
},
{
"key": "openssf_scorecard_code_review",
"name": "OpenSSF Scorecard: Code-Review",
"detail": "Found 0/30 approved changesets -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 15
}
]
},
{
"key": "stewardship",
"band": "at_risk",
"name": "Ownership & stewardship",
"note": null,
"notes": [],
"value": 41,
"inputs": {
"followers": 1,
"owner_type": "Organization",
"is_verified": null,
"owner_login": "lambdadevelopment",
"public_repos": 3,
"account_age_days": 742
},
"components": [
{
"key": "ownership_backing",
"name": "Ownership backing",
"detail": "organization-owned",
"points": 30,
"status": "met",
"details": [
{
"code": "owner_organization",
"params": {}
}
],
"max_points": 30
},
{
"key": "verified_domain",
"name": "Verified domain",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 20
},
{
"key": "owner_reach",
"name": "Owner reach",
"detail": "1 followers of lambdadevelopment",
"points": 2.2,
"status": "partial",
"details": [
{
"code": "owner_followers",
"params": {
"count": 1,
"login": "lambdadevelopment"
}
}
],
"max_points": 25
},
{
"key": "track_record",
"name": "Track record",
"detail": "3 public repos, account ~2 yr old",
"points": 8.4,
"status": "partial",
"details": [
{
"code": "public_repos",
"params": {
"count": 3
}
},
{
"code": "account_age_years",
"params": {
"years": 2
}
}
],
"max_points": 25
}
]
},
{
"key": "package_maintenance",
"band": "excellent",
"name": "Package maintenance",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"packages": [
"lambda-erp",
"@lambda-development/erp-core"
],
"ecosystems": "npm, pypi",
"any_deprecated": false,
"min_days_since_publish": 5
},
"components": [
{
"key": "published_resolvable",
"name": "Published & resolvable",
"detail": "2 package(s) on npm, pypi",
"points": 25,
"status": "met",
"details": [
{
"code": "packages_published",
"params": {
"count": 2,
"ecosystems": "npm, pypi"
}
}
],
"max_points": 25
},
{
"key": "publish_recency",
"name": "Publish recency",
"detail": "latest publish 5 days ago",
"points": 35,
"status": "met",
"details": [
{
"code": "publish_recency",
"params": {
"days": 5
}
}
],
"max_points": 35
},
{
"key": "version_history",
"name": "Version history",
"detail": "63 published versions",
"points": 20,
"status": "met",
"details": [
{
"code": "published_versions",
"params": {
"count": 63
}
}
],
"max_points": 20
},
{
"key": "not_deprecated",
"name": "Not deprecated",
"detail": "active, not deprecated or yanked",
"points": 20,
"status": "met",
"details": [
{
"code": "package_not_deprecated",
"params": {}
}
],
"max_points": 20
}
]
}
],
"description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
},
{
"key": "engineering",
"band": "moderate",
"name": "Engineering Quality",
"value": 66,
"weight": 0.2,
"metrics": [
{
"key": "engineering_practices",
"band": "moderate",
"name": "Engineering practices",
"note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: CI-Tests. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"openssf_scorecard_ci_tests"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 60,
"inputs": {
"has_ci": true,
"has_tests": true,
"has_editorconfig": false,
"has_linter_config": false,
"has_precommit_config": false
},
"components": [
{
"key": "ci_workflows",
"name": "CI workflows",
"detail": "4 workflow(s)",
"points": 24,
"status": "met",
"details": [
{
"code": "ci_workflows",
"params": {
"count": 4
}
}
],
"max_points": 24
},
{
"key": "tests_present",
"name": "Tests present",
"detail": null,
"points": 24,
"status": "met",
"details": [],
"max_points": 24
},
{
"key": "linter_config",
"name": "Linter config",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 16
},
{
"key": "pre_commit_hooks",
"name": "Pre-commit hooks",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 9.6
},
{
"key": "editorconfig",
"name": ".editorconfig",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 6.4
},
{
"key": "openssf_scorecard_ci_tests",
"name": "OpenSSF Scorecard: CI-Tests",
"detail": "no pull request found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 20
}
]
},
{
"key": "documentation",
"band": "good",
"name": "Documentation",
"note": null,
"notes": [],
"value": 75,
"inputs": {
"topics": [],
"has_wiki": true,
"homepage": null,
"has_readme": true,
"has_docs_dir": true,
"has_description": true
},
"components": [
{
"key": "readme",
"name": "README",
"detail": null,
"points": 30,
"status": "met",
"details": [],
"max_points": 30
},
{
"key": "documentation_directory",
"name": "Documentation directory",
"detail": null,
"points": 25,
"status": "met",
"details": [],
"max_points": 25
},
{
"key": "documentation_homepage_site",
"name": "Documentation / homepage site",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 15
},
{
"key": "repository_description",
"name": "Repository description",
"detail": null,
"points": 10,
"status": "met",
"details": [],
"max_points": 10
},
{
"key": "topics",
"name": "Topics",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
},
{
"key": "wiki",
"name": "Wiki",
"detail": null,
"points": 10,
"status": "met",
"details": [],
"max_points": 10
}
]
}
],
"description": "Are baseline engineering and documentation practices in place?"
},
{
"key": "security",
"band": "at_risk",
"name": "Security",
"value": 36,
"weight": 0.16,
"metrics": [
{
"key": "security_posture",
"band": "at_risk",
"name": "Security posture",
"note": "Excluded from scoring (no data or not applicable): CI-Tests, Signed-Releases. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"ci_tests",
"signed_releases"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 36,
"inputs": {
"source": "openssf_scorecard",
"checks_evaluated": 16,
"scorecard_version": "v5.5.0",
"checks_inconclusive": 2,
"scorecard_aggregate": 3.6
},
"components": [
{
"key": "binary_artifacts",
"name": "Binary-Artifacts",
"detail": "no binaries found in the repo",
"points": 7.5,
"status": "met",
"details": [],
"max_points": 7.5
},
{
"key": "branch_protection",
"name": "Branch-Protection",
"detail": "branch protection not enabled on development/release branches",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "ci_tests",
"name": "CI-Tests",
"detail": "no pull request found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 2.5
},
{
"key": "cii_best_practices",
"name": "CII-Best-Practices",
"detail": "no effort to earn an OpenSSF best practices badge detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 2.5
},
{
"key": "code_review",
"name": "Code-Review",
"detail": "Found 0/30 approved changesets -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "contributors",
"name": "Contributors",
"detail": "project has 1 contributing companies or organizations -- score normalized to 3",
"points": 0.8,
"status": "partial",
"details": [],
"max_points": 2.5
},
{
"key": "dangerous_workflow",
"name": "Dangerous-Workflow",
"detail": "no dangerous workflow patterns detected",
"points": 10,
"status": "met",
"details": [],
"max_points": 10
},
{
"key": "dependency_update_tool",
"name": "Dependency-Update-Tool",
"detail": "no update tool detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "fuzzing",
"name": "Fuzzing",
"detail": "project is not fuzzed",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "license",
"name": "License",
"detail": "license file detected",
"points": 2.5,
"status": "met",
"details": [],
"max_points": 2.5
},
{
"key": "maintained",
"name": "Maintained",
"detail": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
"points": 7.5,
"status": "met",
"details": [],
"max_points": 7.5
},
{
"key": "packaging",
"name": "Packaging",
"detail": "packaging workflow detected",
"points": 5,
"status": "met",
"details": [],
"max_points": 5
},
{
"key": "pinned_dependencies",
"name": "Pinned-Dependencies",
"detail": "dependency not pinned by hash detected -- score normalized to 1",
"points": 0.5,
"status": "partial",
"details": [],
"max_points": 5
},
{
"key": "sast",
"name": "SAST",
"detail": "no SAST tool detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "security_policy",
"name": "Security-Policy",
"detail": "security policy file not detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "signed_releases",
"name": "Signed-Releases",
"detail": "no releases found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 7.5
},
{
"key": "token_permissions",
"name": "Token-Permissions",
"detail": "detected GitHub workflow tokens with excessive permissions",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "vulnerabilities",
"name": "Vulnerabilities",
"detail": "11 existing vulnerabilities detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
}
]
},
{
"key": "high_risk_jurisdiction_exposure",
"band": "excellent",
"name": "High-Risk Jurisdiction Exposure",
"note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
"notes": [
{
"code": "jurisdiction_evidence_limits",
"params": {}
}
],
"value": 100,
"inputs": {
"meaning": "self-published location evidence; not nationality or citizenship",
"red_flag": false,
"exposures": [],
"policy_countries": [
"Russia",
"Iran",
"North Korea"
],
"review_only_matches": 0,
"assessed_self_published_locations": 1
},
"components": [
{
"key": "policy_exposure_multiplier",
"name": "Policy exposure multiplier",
"detail": "no confirmed policy-scope location match",
"points": 100,
"status": "met",
"details": [
{
"code": "jurisdiction_no_match",
"params": {}
}
],
"max_points": 100
}
]
}
],
"description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
},
{
"key": "ai_readiness",
"band": "good",
"name": "AI Readiness",
"value": 70,
"weight": 0,
"metrics": [
{
"key": "ai_agent_context",
"band": "excellent",
"name": "Agent context & guidance",
"note": null,
"notes": [],
"value": 85,
"inputs": {
"has_llms_txt": false,
"legible_history_share": 0.92,
"agent_instruction_files": [
"CLAUDE.md"
],
"agent_instruction_max_bytes": 1598
},
"components": [
{
"key": "agent_instructions",
"name": "Agent instructions",
"detail": "CLAUDE.md",
"points": 45,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "CLAUDE.md"
}
}
],
"max_points": 45
},
{
"key": "machine_readable_docs_llms_txt",
"name": "Machine-readable docs (llms.txt)",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 15
},
{
"key": "legible_commit_history",
"name": "Legible commit history",
"detail": "92 of 100 human commits state their intent (structured subject or explanatory body)",
"points": 40,
"status": "met",
"details": [
{
"code": "legible_history",
"params": {
"legible": 92,
"sampled": 100
}
}
],
"max_points": 40
}
]
},
{
"key": "ai_verify_loop",
"band": "moderate",
"name": "Verify loop (build / test / typecheck)",
"note": null,
"notes": [],
"value": 54,
"inputs": {
"has_nix": false,
"has_tests": true,
"lockfiles": [
"package-lock.json"
],
"has_dockerfile": true,
"typed_language": false,
"bootstrap_files": [],
"has_devcontainer": false,
"has_linter_config": false,
"typecheck_configs": [
"frontend/tsconfig.json"
],
"agent_commit_share": 0.78,
"toolchain_manifests": [],
"dependency_bot_commit_share": 0
},
"components": [
{
"key": "one_command_bootstrap",
"name": "One-command bootstrap",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 18
},
{
"key": "automated_tests",
"name": "Automated tests",
"detail": null,
"points": 22,
"status": "met",
"details": [],
"max_points": 22
},
{
"key": "lint_format_config",
"name": "Lint / format config",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 11
},
{
"key": "static_type_checking",
"name": "Static type checking",
"detail": "frontend/tsconfig.json",
"points": 11,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "frontend/tsconfig.json"
}
}
],
"max_points": 11
},
{
"key": "reproducible_environment",
"name": "Reproducible environment",
"detail": "Dockerfile, lockfile",
"points": 10,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "Dockerfile, lockfile"
}
}
],
"max_points": 10
},
{
"key": "demonstrated_agent_practice",
"name": "Demonstrated agent practice",
"detail": "78 of the last 100 commits agent-authored or agent-credited",
"points": 10,
"status": "met",
"details": [
{
"code": "agent_authored_commits",
"params": {
"count": 78,
"sampled": 100
}
}
],
"max_points": 10
},
{
"key": "automated_maintenance",
"name": "Automated maintenance",
"detail": "no automated dependency updates observed",
"points": 0,
"status": "missed",
"details": [
{
"code": "no_dependency_automation",
"params": {}
}
],
"max_points": 8
},
{
"key": "openssf_scorecard_pinned_dependencies",
"name": "OpenSSF Scorecard: Pinned-Dependencies",
"detail": "dependency not pinned by hash detected -- score normalized to 1",
"points": 1,
"status": "partial",
"details": [],
"max_points": 10
}
]
},
{
"key": "ai_code_legibility",
"band": "good",
"name": "Code legibility for models",
"note": null,
"notes": [],
"value": 81,
"inputs": {
"primary_language": "Python",
"largest_source_bytes": 181453,
"source_files_sampled": 145,
"oversized_source_files": 3
},
"components": [
{
"key": "type_checkable_code",
"name": "Type-checkable code",
"detail": "Python with type-check config (frontend/tsconfig.json)",
"points": 27,
"status": "partial",
"details": [
{
"code": "typecheck_config_language",
"params": {
"files": "frontend/tsconfig.json",
"language": "Python"
}
}
],
"max_points": 45
},
{
"key": "manageable_file_sizes",
"name": "Manageable file sizes",
"detail": "3/145 source files over 60KB",
"points": 53.9,
"status": "partial",
"details": [
{
"code": "oversized_source_files",
"params": {
"kb": 60,
"sampled": 145,
"oversized": 3
}
}
],
"max_points": 55
}
]
}
],
"description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
}
],
"metrics_version": "1.13.0"
},
"warnings": [
"Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token",
"GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
"deps.dev does not index pypi:lambda-erp@0.3.4; advisories assessed against the repository dependency graph instead"
],
"report_type": "repository",
"generated_at": "2026-07-22T15:11:17.963013Z",
"schema_version": "0.26.0",
"badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/l/lambdadevelopment/lambda-erp.svg",
"full_name": "lambdadevelopment/lambda-erp",
"license_state": "standard",
"license_spdx": "Apache-2.0"
}