{"id":49553064,"url":"https://github.com/doeixd/gen2","last_synced_at":"2026-05-03T00:31:47.085Z","repository":{"id":354903129,"uuid":"1224937257","full_name":"doeixd/gen2","owner":"doeixd","description":"A typed, spec-driven domain model compiler. Define entities, relations, queries, functions, and UI components with static checks and multi-target code generation.","archived":false,"fork":false,"pushed_at":"2026-04-30T19:31:40.000Z","size":784,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-30T21:17:33.848Z","etag":null,"topics":["authorization","code-generation","codegen","compiler","domain-modeling","full-stack","orm","reactive-programming","typescript","ui-framework"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/doeixd.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-04-29T19:30:08.000Z","updated_at":"2026-04-30T19:31:45.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/doeixd/gen2","commit_stats":null,"previous_names":["doeixd/gen2"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/doeixd/gen2","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doeixd%2Fgen2","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doeixd%2Fgen2/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doeixd%2Fgen2/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doeixd%2Fgen2/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/doeixd","download_url":"https://codeload.github.com/doeixd/gen2/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doeixd%2Fgen2/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32554059,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-03T00:31:16.350Z","status":"ssl_error","status_checked_at":"2026-05-03T00:31:15.546Z","response_time":132,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["authorization","code-generation","codegen","compiler","domain-modeling","full-stack","orm","reactive-programming","typescript","ui-framework"],"created_at":"2026-05-03T00:31:46.406Z","updated_at":"2026-05-03T00:31:47.075Z","avatar_url":"https://github.com/doeixd.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# gen2\n\nA **typed semantic IR SDK for full-stack applications**.\n\n\u003e It lets you describe your application's domain, data, actions, rules, auth, UI, routes, forms, reactivity, and runtime requirements as typed, inspectable TypeScript values — then checks, derives, generates, visualizes, and evolves the app from that model.\n\nIt is a language inside TypeScript, but not just for syntax convenience. Its real purpose is to make the **meaning of the app** explicit.\n\n---\n\n## What is gen2?\n\nMost apps are built out of scattered implementation fragments:\n\n```\ndatabase schema\nORM models\nAPI handlers\nReact components\nforms\nvalidation schemas\nauth middleware\nquery cache keys\nroute loaders\nmutation invalidation\ntests\ndocs\n```\n\nThe actual product meaning is hidden across all of that.\n\ngen2 says:\n\n```\nDefine the app semantics once as static typed IR.\nThen derive the runtime implementation from that.\n```\n\nSo instead of the source of truth being \"whatever handwritten code happens to exist,\" the source of truth becomes a graph of typed domain objects:\n\n```\nEntity\nField\nSemanticType\nExpr\nPredicate\nQueryFunction\nActionFunction\nRule\nPolicy\nKey\nResource\nRoute\nForm\nView\nService\nTarget\nArtifact\n```\n\nThat graph can be checked, transformed, generated, and understood by tools.\n\n### The philosophy\n\n```\nApplication behavior should be data first.\nDomain semantics should be inspectable.\nGenerated code should be an interpretation, not the source of truth.\nType inference is part of the product.\nTargets are plugins, not hardcoded assumptions.\nReactivity, routing, auth, UI, and CRUD should derive from one graph.\nRules should be pure predicates.\nEffects should be explicit.\nFallbacks should be visible.\nDiagnostics should explain degradation and unsafe choices.\n```\n\nThe guiding preference is:\n\n```\nDescribe what the app means.\nLet the compiler decide what can be generated safely.\n```\n\nNot:\n\n```\nWrite framework glue everywhere and hope it stays consistent.\n```\n\n---\n\n## What problem it solves\n\nModern full-stack apps have many repeated obligations.\n\nWhen you add a field, action, or policy, you may need to update:\n\n```\ndatabase schema\nmigration\nvalidation\nAPI input type\nAPI output type\nform field\nlist column\ndetail view\nauth policy\nfield-level permissions\ncache invalidation\nroute loader\nOpenAPI/RPC client\ntests\ndocs\n```\n\nHumans forget these. AI agents forget these. Frameworks usually do not know enough to catch them.\n\ngen2 tries to encode those obligations into the IR graph so that changes become checkable.\n\nFor example:\n\n```\nProject.status changes\n  -\u003e update transition rules\n  -\u003e update editability rules\n  -\u003e update list filters\n  -\u003e update mutation write checks\n  -\u003e update invalidation\n  -\u003e update generated tests\n```\n\nThat is the reason for being.\n\n---\n\n## Features\n\n- **Entity system** — identity-bearing domain objects with typed fields, refs, transitions, and presence conditions.\n- **Rich type system** — semantic types (`uuid`, `email`, `money`, `datetime`, …) backed by precise physical representations (`u8`…`i128`, `f32`/`f64`, `text`, `fixedBytes`, …).\n- **Expression algebra** — static, typed ASTs for literals, field refs, unary/binary/comparison/aggregate operations, and predicates.\n- **Query system** — `SELECT`, `WHERE`, `JOIN`, `ORDER BY`, `LIMIT`, plus query-backed fields and cross-store composition planning.\n- **Function taxonomy** — `StaticFunction`, `ExprFunction`, `PredicateFunction`, `QueryFunction`, `ActionFunction`, `PatchFunction`, `PlanFunction`.\n- **Storage mapping** — map entity fields to tables, columns, collections, and keyspaces with type-compatibility checks.\n- **Relations** — one-to-one, one-to-many, many-to-one, many-to-many with integrity modes, foreign keys, and referential actions.\n- **Authorization** — per-action policies (`AllowAuthenticated`, `AllowRole`, `AllowOwner`, `AllowRelation`) with SQL translation and safe client exposure checks.\n- **Events \u0026 reducers** — event definitions, emissions, monoidal reducers, and subscriptions.\n- **UI system** — platform-agnostic views, slots, components, forms, styles, behaviors, themes, and renderers.\n- **Plugin architecture** — extend the kernel with custom helpers, targets, runtimes, stores, metadata namespaces, and codegen hooks.\n- **Lifecycle runner** — `check` validates plugins, targets, and module invariants; `generate` invokes plugin codegen hooks.\n\n---\n\n## Quick start\n\n```ts\nimport { createGen, lifecycle } from \"gen2\";\n\nconst { gen, ctx } = createGen();\n\nconst User = gen.entity(\"User\", {\n  id: gen.uuid(),\n  email: gen.email(),\n  displayName: gen.string(),\n  role: gen.enumOf(\"Role\", [\"admin\", \"user\"]),\n});\n\nconst Post = gen.entity(\"Post\", {\n  id: gen.uuid(),\n  title: gen.string(),\n  authorId: gen.uuid(),\n});\n\ngen.relation({\n  name: \"author\",\n  kind: \"many_to_one\",\n  from_entity: Post,\n  to_entity: User,\n  from_field: Post.fields.authorId,\n  to_field: User.fields.id,\n  integrity: { kind: \"database_foreign_key\" },\n});\n\nconst result = lifecycle.check(ctx);\nconsole.log(result.status); // \"ok\" | \"has_errors\" | \"has_warnings\"\n```\n\n---\n\n## The source of truth\n\nA key design principle is that queries and actions remain canonical:\n\n```\ngen.func.query\ngen.func.action\n```\n\nReads and writes live there.\n\nEverything else interprets them:\n\n```\nreactivity\nrouting\nhydration\nUI\nforms\nsingle-flight\nclients\ndevtools\ntests\ndocs\n```\n\nThis matters because it prevents the app from fragmenting into separate systems.\n\nA query is not separately defined for API, UI, cache, and route loader. It is one static function that can be used by all of them.\n\n---\n\n## Entities and semantic types\n\nEntities define the domain:\n\n```\nUser\nProject\nInvoice\nOrder\nMembership\n```\n\nFields carry semantic types:\n\n```\nemail\nuuid\nmoney\ndate\nenum\nrole\nstatus\nmarkdown\nsafeHtml\n```\n\nThe point is not just to know that something is a `string`; it is to know what it **means**.\n\nThat lets generators make better decisions:\n\n```\nemail field -\u003e email input + validation\nmoney field -\u003e decimal/db mapping + currency display\nstatus enum -\u003e transition checks + badges\nserver-only field -\u003e exclude from client bundles\nhidden field -\u003e omit from forms/views\n```\n\nSemantic types are what make generated app code less generic.\n\n---\n\n## Static expressions\n\nTyped expressions are the glue.\n\nThey let the system represent logic without opaque callbacks:\n\n```\nfield comparisons\npredicates\nquery filters\ncomputed projections\naction updates\nvalidation conditions\npolicy rules\ntransition checks\nderived values\n```\n\nBecause expressions are static IR, the compiler can inspect them.\n\nThat enables:\n\n```\nSQL generation\ndependency extraction\nauth placement\nreactivity derivation\ntest generation\ndiagnostics\n```\n\nThis is one of the most important ideas: logic should be represented as typed, inspectable expression trees when it is meant to be portable.\n\n---\n\n## Queries and actions\n\nQueries are typed read functions.\n\nActions are typed write/effect functions.\n\nThey carry:\n\n```\ninput type\noutput type\nerror type\nrequirements\neffects\nbody IR\nreactivity metadata\nauth constraints\n```\n\nA query might become:\n\n```\nSQL SELECT\nHTTP endpoint\nRPC method\nroute loader\nReact query hook\nOpenAPI operation\ntest fixture\n```\n\nAn action might become:\n\n```\nSQL INSERT/UPDATE/DELETE\nAPI mutation\nTanStack mutation\nEffect action\naudit event\noutbox job\ncache invalidation plan\nsingle-flight refresh\n```\n\nThe power comes from defining the operation once and generating multiple target artifacts.\n\n---\n\n## Rules\n\nRules are named, typed predicates.\n\nThey answer questions like:\n\n```\ncanViewProject(actor, project)\ncanEditInvoice(actor, invoice)\nisOrderShippable(order)\nisProjectOverdue(project)\nisFieldEditable(actor, resource, field)\n```\n\nBut rules are not just boolean helpers. Because they are inspectable, the system can know:\n\n```\nwhich fields they read\nwhich relations they depend on\nwhether they can become SQL\nwhether they can be used as a client hint\nwhich mutations may affect them\nwhich tests should be generated\n```\n\nRules are the semantic layer for business logic.\n\nThey should be pure. Effects belong elsewhere.\n\n---\n\n## Auth\n\nAuth is a consumer of rules.\n\nA rule says:\n\n```\nproject.ownerId == actor.id\n```\n\nAuth says:\n\n```\nactor may update Project when canEditProject(actor, project)\n```\n\nThe system can model access at multiple levels:\n\n```\nentity.read\nentity.create\nentity.update\nentity.delete\nfield.read\nfield.write\nrelation.link\nrelation.unlink\naction.execute\nquery.filter\nroute.enter\nform.submit\nui.hint\n```\n\nThis is much richer than a single middleware check.\n\nIt lets the compiler generate:\n\n```\nSQL WHERE filters\nserver item checks\nfield redaction\ninput write masks\nform disabled states\nroute guards\nclient hints\npolicy tests\naccess matrix docs\n```\n\nAnd importantly, it can reject unsafe choices, such as list authorization that cannot be pushed into the database.\n\n---\n\n## CRUD\n\nCRUD is not meant to be a separate magic shortcut. It should expand into the same canonical IR.\n\nFor an entity like `Project`, CRUD can generate:\n\n```\nlistProjects\ngetProjectById\ncreateProject\nupdateProject\ndeleteProject\nProjectCreateForm\nProjectEditForm\nProjectList\nProjectDetailRoute\nproject.detail key\nproject.list key\nauth policies\nfield write checks\ninvalidation plans\ntests\ndocs\n```\n\nBut all of those are normal queries, actions, keys, routes, forms, and policies.\n\nThat means CRUD does not become a dead-end abstraction. It becomes a fast way to produce a complete, inspectable full-stack slice.\n\n---\n\n## Keys and reactivity\n\nThe key system gives the app a typed address space for reactive data.\n\nExamples:\n\n```\nproject.detail({ id })\nproject.list({ actorId, filter })\nproject.collection()\nrule.canEditProject({ actorId, projectId })\nProject.field.status({ id })\n```\n\nQueries declare the keys they read or produce. Actions declare or derive the keys they invalidate.\n\nRules make this more powerful. If a rule reads `Project.visibility`, and a query uses that rule, and a mutation writes `Project.visibility`, the compiler can infer that the query's key may be stale.\n\nThat gives you rule-derived reactivity:\n\n```\nmutation writes field\n  -\u003e rule depends on field\n  -\u003e query uses rule\n  -\u003e resource has key\n  -\u003e invalidate or refresh key\n```\n\nThis is how cache invalidation becomes a graph problem instead of handwritten bookkeeping.\n\n---\n\n## Reactive graph\n\nThe reactive graph is the heart of the architecture.\n\nIt connects:\n\n```\nentities\nfields\nqueries\nactions\nrules\npolicies\nkeys\nresources\nmutations\nforms\nroutes\ncomponents\nservices\ntargets\n```\n\nWith edges like:\n\n```\nreads\nwrites\nuses\ninvalidates\nderives\nrequires\nemits\nsubscribes\nhydrates\ntransports\n```\n\nOnce this graph exists, the compiler can answer questions like:\n\n```\nWhat becomes stale after this mutation?\nWhich routes depend on this query?\nWhich UI reads this key?\nWhich policies depend on this field?\nWhich generated tests are needed?\nWhat breaks if this enum adds a value?\nWhich target cannot support this feature?\n```\n\nThat is the big power move.\n\n---\n\n## Targets\n\ngen2 is target-agnostic.\n\nThe same IR could generate different stacks:\n\n```\nPostgres\nSQLite\nMongo\nHono\nOpenAPI\nEffect\nReact\nTanStack Query\nTanStack Router\nSvelte\nVue\nSolid\nstandard-schema\nZod-like validators\nTailwind UI\nadmin screens\ndocs\ntests\ndevtools\n```\n\nThe goal is not to hardcode one blessed stack. The goal is:\n\n```\nSame app semantics.\nDifferent target interpretations.\n```\n\nSo stack preferences become configuration:\n\n```\ndatabase: Postgres\napi: Hono\nfrontend: React\nrouter: TanStack Router\nreactivity: TanStack Query\nvalidation: standard-schema\nstyling: Tailwind\n```\n\nThe generator picks supported plans and emits diagnostics for unsupported features.\n\n---\n\n## Progressive enhancement\n\nAnother philosophical piece is that features should have explicit fallback plans.\n\nFor example:\n\n```\nbest case:\n  optimistic update with precise rollback\n\nfallback:\n  pending state + refetch\n\nlast resort:\n  disable submit until server response\n```\n\nOr:\n\n```\nbest case:\n  SQL auth filter\n\nfallback:\n  bounded server check\n\nreject:\n  unsafe unbounded post-filter\n```\n\nThe system should not silently degrade. It should say what it did and why.\n\n---\n\n## Reactions\n\nRules can also connect to reactions.\n\nA rule remains pure:\n\n```\nproject is overdue\n```\n\nA reaction says:\n\n```\nwhen project becomes overdue, send notification\n```\n\nThis should compile to an inspectable effect plan:\n\n```\ncondition\nselected input\naction to run\nrequirements\neffects\nidempotency key\ndelivery plan\nretry policy\n```\n\nThis matters because effectful behavior needs safety: outbox, idempotency, retries, audit logs, and clear delivery guarantees.\n\n---\n\n## IVM and derived data\n\nRules can also define derived facts:\n\n```\nVisibleProject(userId, projectId)\nOverdueProject(projectId)\nEditableInvoice(userId, invoiceId)\n```\n\nAt first, this can drive broad invalidation.\n\nLater, it can drive materialized views or incremental view maintenance.\n\nThe progression should be:\n\n```\ndependency extraction\nconservative invalidation\nkey-aware invalidation\npredicate-aware patches\nIVM/materialized maintenance\n```\n\nThe value is that derived data comes from the same semantic rules used for auth, UI, and reactivity.\n\n---\n\n## Why this matters for AI agents\n\ngen2 is especially compelling in the AI-agent era because agents need structured context.\n\nToday, an agent modifying an app has to infer intent from scattered code. It may update the handler but forget the form. It may update the field but forget the auth rule. It may change a mutation but forget invalidation.\n\nWith gen2, the agent can operate on a semantic model.\n\nInstead of saying:\n\n```\nedit these seven files\n```\n\nThe agent can say:\n\n```\nAdd archivedAt to Project.\nMake archived projects read-only.\nHide them from the default list.\nAllow admins to restore them.\n```\n\nThen the compiler can produce or check:\n\n```\nfield addition\nmigration\nupdate input changes\ntransition rule\nauth policy changes\nlist filter changes\nform disabled state\nrestore action\ncache invalidation\ngenerated tests\ndocs\n```\n\nThat is the future-facing reason this is powerful.\n\nAI agents are better when they can edit **intent**, not just text.\n\n---\n\n## What makes it different from ordinary codegen\n\nOrdinary codegen often means:\n\n```\ngenerate scaffolding once\nthen hand-edit forever\n```\n\ngen2 wants:\n\n```\ndefine semantic IR\ncheck it\nderive graph\ngenerate targets\nkeep regenerating safely\n```\n\nThat is not scaffolding. That is a compiler pipeline.\n\nThe generated artifacts are downstream of the source model.\n\n---\n\n## What makes it different from a normal framework\n\nA normal framework gives you conventions and runtime APIs.\n\ngen2 gives you an application model.\n\nFramework:\n\n```\nwrite code in my lifecycle\n```\n\ngen2:\n\n```\ndescribe your app semantics\nI will generate framework code as a target\n```\n\nThat distinction is huge.\n\nIt means React, Hono, TanStack Query, SQL, OpenAPI, and devtools are not the app. They are outputs.\n\n---\n\n## The power\n\nThe power is coherence.\n\nOne domain change can propagate through:\n\n```\ntypes\nqueries\nactions\nauth\nforms\nroutes\nkeys\nreactivity\ntests\ndocs\ngenerated UI\n```\n\nOne rule can power:\n\n```\nserver enforcement\nSQL filtering\nclient hints\nfield permissions\nroute guards\ntest cases\nreactive invalidation\nIVM\n```\n\nOne mutation can expose:\n\n```\nwrite set\nauth checks\nfield transition checks\naudit events\nkey invalidation\nreactions\nsingle-flight refresh\n```\n\nThe power is not that it writes code for you.\n\nThe power is that it **knows what the code means**.\n\n---\n\n## Architecture\n\nThe codebase is organized into modules that mirror the Allium specification in `spec/`:\n\n- `src/core/` — kernel, plugins, targets, refs, diagnostics, artifacts, contracts, actors, config\n- `src/types/` — semantic types, representations, operations, traits, runtimes\n- `src/entity/` — entities, fields, transitions\n- `src/expression/` — AST, builders, checks, planning\n- `src/storage/` — stores, tables, columns, mappings, projections\n- `src/relation/` — relations, graphs, integrity, foreign keys\n- `src/query/` — query expressions, projections, joins, planners, cross-store queries\n- `src/function/` — static, expr, predicate, query, action, patch, and plan functions\n- `src/api/` — resources, routes, getters, mutators\n- `src/ui/` — views, slots, components, forms, styles, behaviors, themes\n- `src/authz/` — policies, rules, translations, client exposure\n- `src/events/` — events, emissions, reducers, subscriptions, outbox\n- `src/lifecycle/` — phases, check/generate runner, cross-store planning\n\nEach module exports pure `check*` functions that return `Diagnostic[]`, making the validation pipeline easy to test and compose.\n\n---\n\n## Development\n\n```bash\n# Install dependencies\nvp install\n\n# Run type checks, lint, and format\nvp check\n\n# Run tests\nvp test\n\n# Build library for production\nvp pack\n```\n\n---\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdoeixd%2Fgen2","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdoeixd%2Fgen2","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdoeixd%2Fgen2/lists"}