gg_dna 4.0.0 copy "gg_dna: ^4.0.0" to clipboard
gg_dna: ^4.0.0 copied to clipboard

discontinuedreplaced by: helix

The DNA engine - resolves DNA packages declared as dev-dependencies, merges their dna folders and instantiates configs, docs, scripts and agent skills into the target repo.

gg_dna #

gg_dna is the DNA engine — it is not the DNA itself. The DNA (the guides, scripts, configurations and agent skills a project inherits) lives in separate DNA packages: base_dna, dna_dart, dna-ts, ds-dna, … Each of them ships a dna/ folder that mirrors a project root.

This engine resolves the DNA packages a project depends on, merges their dna/ folders into one tree and copies the result to its real locations (.vscode/settings.json, LICENSE, doc/, .claude/skills/, …). These copies are called instances — and a placed test guarantees on every test run that they always match the generated originals.

Quick start #

  1. Declare DNA packages as dev-dependencies:

    // package.json (TypeScript projects)
    { "devDependencies": { "dna-ts": "^1.0.0" } }
    
    # pubspec.yaml (Dart projects)
    dev_dependencies:
      dna_dart: ^1.0.0
      gg_dna: ^5.0.0
    
  2. Install (pnpm install / dart pub get) and run once:

    gg_dna init
    

    This places the DNA wrapper test (test/dna/dna_test.dart and/or test/dna/dna.spec.ts), a .gg/dna.json skeleton and the !.gg/dna.json gitignore exception. Commit.

  3. Run your tests. The first run instantiates the DNA and commits what it generated as #gg: generated DNA. From now on every test run keeps the project in sync.

Distribution: dev-dependencies + inheritance tree #

DNAs are normal packages (npm, for Dart-reachable DNAs additionally pub). A DNA declares its parent DNAs as regular dependencies — npm and pub therefore install the whole inheritance tree transitively; gg_dna clones nothing. The engine locates packages via node_modules/ and .dart_tool/package_config.json, reads each DNA's own .gg/dna.json and expands the tree recursively: parents before children, diamonds deduplicated (first topological position wins), cycles are errors.

Order: by default DNAs apply in the order they appear in package.json/pubspec.yaml (a dependency counts as DNA when the installed package contains a dna/ folder). An explicit order in .gg/dna.json overrides this. The last override wins.

Configuration: .gg/dna.json #

The only place DNA configuration lives (all keys optional, JSONC tolerated):

{
  "role": "project", // "dna" for DNA packages themselves
  "order": ["base_dna", "dna_dart"],
  "vars": { "projectName": "my_project" },
  "fileNaming": "snake_case", // camelCase | kebab-case | keep
  "dependencies": { "base_dna": { "path": "../base_dna" } },
  "config": {
    "claude": { "claude_md": { "include": ["doc/conventions"] } },
  },
}
  • role: "project" (default): dna/ is fully generated by the engine.
  • role: "dna": the repo authors its dna/ by hand; it is the last (winning) layer of its own instantiation and is never overwritten.
  • dependencies holds path overrides only (local development workspaces) — versions live in the package manifests.
  • dna: blocks in pubspec.yaml/package.json and dna.yaml are migration errors since 5.0.

The replica layout #

dna/ mirrors the project root:

Path in the DNA Instantiated to
dna/.vscode/settings.json .vscode/settings.json
dna/LICENSE LICENSE
dna/doc/develop.md doc/develop.md
dna/scripts/create-branch.js scripts/create_branch.js¹
dna/.claude/skills/init/SKILL.md .claude/skills/init/SKILL.md
dna/_vars.json — (private)

¹ file naming converted for a Dart project, see below.

  • Private: path segments starting with _ (e.g. _vars.json) stay inside dna/ and are never instantiated.
  • Public: everything else — including dotfiles — becomes an instance.
  • Consumed by the engine itself: *.overrides.md, *.overrides.json sidecars, plus its own bookkeeping — dna/_dna.json (layers and hashes) and dna/_instances.json (the project files the DNA owns). The effective variables are not bookkeeping: they are content and live in dna/_vars.json.
  • Forbidden instance targets: .git/** and CLAUDE.md (the latter is managed via the claude_md block below).

The placed test: instantiate + verify in one #

Every test run executes the engine (Dart: in-process via the gg_dna dev-dependency; TypeScript: via the npm package @tssuite/gg-dna, the gg_dna engine compiled to WebAssembly with node callbacks injected):

  • Instance modified by hand → the test fails and leaves the file untouched. The report names the DNA source the file is generated from, so the fix is obvious:

    Generated files modified by hand:
    Move edits from .vscode/settings.json to dna_dart/dna/.vscode/settings.overrides.json.
    
  • DNA updated (new dependency versions, changed local DNA) → the engine rewrites dna/, the instances and its bookkeeping and commits exactly those files as #gg: generated DNA — generated content is machine-owned and never clutters your working tree. Without a repository or a git identity the files stay for a manual commit and the run fails once.

  • Everything up to date → green, no writes.

  • Per-file guard: every existing file a run would overwrite or delete must be committed. If one of them carries uncommitted work (modified, staged or untracked), the run fails without writing and reports each file the same way — Move edits from <instance> to <DNA source>. (headline: Generated files carry invalid changes:) Unrelated dirty files never block a run, so every overwrite stays recoverable via git.

Existing project files that a DNA also ships are adopted (overwritten — git history is the backup, which is exactly what the per-file guard enforces). Instances no longer produced by any DNA are removed, together with folders they leave empty; locally modified ones are kept with a warning.

Markdown overrides #

Unchanged from 4.0, now across the whole replica: ## [@tag] Heading marks a replaceable section, {{@tag:default}} a replaceable string. A higher layer ships X.overrides.md next to the same path with heading-form or <!-- @tag --> … <!-- @tag --> blocks; global.overrides.md in the dna/ root rewrites string placeholders in all merged .md files. Markers survive layer application; the final render strips them. Content in code fences and inline code is immune.

JSON overrides #

A same-path X.json in a later layer replaces the file. A sidecar X.overrides.json merges field-wise:

  • objects deep-merge (default), scalars replace
  • null deletes the key
  • "key!" replaces the value outright (no merge)
  • "key+" joins arrays (append, deduplicated)
// base_dna: dna/.vscode/extensions.json
{ "recommendations": ["esbenp.prettier-vscode"] }
// dna_dart: dna/.vscode/extensions.overrides.json
{ "recommendations+": ["dart-code.dart-code"] }
// instance: .vscode/extensions.json
{ "recommendations": ["esbenp.prettier-vscode", "dart-code.dart-code"] }

JSONC input (comments, trailing commas) is tolerated; structurally patched files are re-emitted comment-free, untouched files are copied byte-identical. YAML supports whole-file replacement only — X.overrides.yaml is an error.

Variables #

Defined in dna/_vars.json (camelCase keys without prefix), deep- merged across all layers, finally overridden by vars in the target's .gg/dna.json:

{ "copyrightHolder": "ggsuite", "projectName": "unnamed" }

References carry the dna prefix and are replaced case-adaptively in every text file of the merged tree:

Reference Replacement
dnaProjectName camelCase (myProject)
DnaProjectName PascalCase (MyProject) — class names
dna_project_name snake_case (my_project)
DNA_PROJECT_NAME SCREAMING_SNAKE (MY_PROJECT)
dna-project-name kebab-case (my-project)

Non-identifier values (spaces, sentences — e.g. "MEGA TARGET") are inserted verbatim for every form. Unknown references stay literal.

File naming conversion #

DNA files are authored in canonical kebab-case. At instantiation they are converted to the target standard — pubspec.yaml present → snake_case, otherwise package.json present → kebab-case, otherwise keep (overridable via fileNaming). Only the part before the first dot of purely lowercase segments converts (dna-test.dartdna_test.dart; .spec.ts, .code-snippets, LICENSE, README.md stay untouched). References to renamed files are rewritten inside text instances; the dna/ originals keep canonical names.

CLAUDE.md and skills #

  • Skills are plain instances: dna/.claude/skills/<name>/SKILL.md.claude/skills/<name>/SKILL.md.
  • CLAUDE.md keeps the managed block: config.claude.claude_md.include lists files/folders (human documentation!) that get one @-import line each between <!-- gg_dna:claude_md:start/end -->. Content outside the block is never touched. All documentation is written for humans — the AI consumes the same files.

Engine API #

import 'package:gg_dna/gg_dna.dart';

await runDnaTest();                  // what the placed test calls
final result = instantiateDna(       // programmatic access
  host: IoDnaHost(),
  targetRoot: '.',
  baseVersion: ggDnaVersion,
);

The engine core is free of dart:io/Process — all host access goes through the injectable DnaHost interface (IoDnaHost for the CLI and Dart tests, callback-based hosts for the WebAssembly bridge @tssuite/gg-dna).

Migration from 4.x #

  1. Move dna/src/* to dna/* in every DNA repo (dna/src is a hard error). Prefix DNA-internal folders with _.
  2. Move the dna: block from pubspec.yaml/package.json/dna.yaml to .gg/dna.json; drop git: layers and version: entries — declare DNAs as dev-dependencies instead.
  3. Replace gg_dna sync invocations with gg_dna init (once) and your normal test run.
  4. config: claude: skills: is gone — ship skills at dna/.claude/skills/<name> instead.
  5. .gg_dna_staging/.gg_dna_backup are no longer created and can be removed from .gitignore.
0
likes
0
points
456
downloads

Publisher

verified publisherinlavigo.com

Weekly Downloads

The DNA engine - resolves DNA packages declared as dev-dependencies, merges their dna folders and instantiates configs, docs, scripts and agent skills into the target repo.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

args, gg_args, gg_console_colors, gg_hash, gg_log, path, yaml

More

Packages that depend on gg_dna