Migrate Internal Package into Ghost
TryGhost/Ghost
Moves a package from another TryGhost repository into Ghost as an internal workspace package while keeping its Git history, with checkpoints for the steps that need an administrator.
Guides merging a standalone Grails plugin repository into the grails-core monorepo as Gradle subprojects that use the shared build, publishing, docs and CI.
$ npx skills add apache/grails-core --skill mono-repo-integration -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install apache/grails-core mono-repo-integration --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/apache/grails-core.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/mono-repo-integration .claude/skills/mono-repo-integration && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "mono-repo-integration" agent skill from https://github.com/apache/grails-core/tree/8.0.x/.agents/skills/mono-repo-integration into .claude/skills/mono-repo-integration/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "mono-repo-integration", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/apache/grails-core/tree/8.0.x/.agents/skills/mono-repo-integrationType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add apache/grails-core --skill mono-repo-integration -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install apache/grails-core mono-repo-integration --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/apache/grails-core.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.agents/skills/mono-repo-integration .agents/skills/mono-repo-integration && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "mono-repo-integration" agent skill from https://github.com/apache/grails-core/tree/8.0.x/.agents/skills/mono-repo-integration into .agents/skills/mono-repo-integration/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "mono-repo-integration", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add apache/grails-core --skill mono-repo-integration -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install apache/grails-core mono-repo-integration --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/apache/grails-core.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.agents/skills/mono-repo-integration .cursor/skills/mono-repo-integration && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "mono-repo-integration" agent skill from https://github.com/apache/grails-core/tree/8.0.x/.agents/skills/mono-repo-integration into .cursor/skills/mono-repo-integration/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "mono-repo-integration", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/apache/grails-core.git --path .agents/skills/mono-repo-integration--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add apache/grails-core --skill mono-repo-integration -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install apache/grails-core mono-repo-integration --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/apache/grails-core.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.agents/skills/mono-repo-integration .gemini/skills/mono-repo-integration && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "mono-repo-integration" agent skill from https://github.com/apache/grails-core/tree/8.0.x/.agents/skills/mono-repo-integration into .gemini/skills/mono-repo-integration/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "mono-repo-integration", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install apache/grails-core mono-repo-integrationInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add apache/grails-core --skill mono-repo-integration -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/apache/grails-core.git skills-src && mkdir -p .github/skills && cp -r skills-src/.agents/skills/mono-repo-integration .github/skills/mono-repo-integration && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "mono-repo-integration" agent skill from https://github.com/apache/grails-core/tree/8.0.x/.agents/skills/mono-repo-integration into .github/skills/mono-repo-integration/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "mono-repo-integration", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add apache/grails-core --skill mono-repo-integration -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install apache/grails-core mono-repo-integration --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/apache/grails-core.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.agents/skills/mono-repo-integration .opencode/skills/mono-repo-integration && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "mono-repo-integration" agent skill from https://github.com/apache/grails-core/tree/8.0.x/.agents/skills/mono-repo-integration into .opencode/skills/mono-repo-integration/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "mono-repo-integration", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
mono-repo-integrationGuides merging a standalone Grails plugin repository into the grails-core monorepo as Gradle subprojects that use the shared build, publishing, docs and CI.
This skill describes a repeatable process for folding a plugin repository that used to live on its own, such as grails-spring-security or grails-redis, into the grails-core monorepo. The plugin's source is first copied into a top-level folder, then its own build, release and CI machinery is stripped out and each module is rewired onto the monorepo's shared Gradle configuration, publishing setup, documentation guide and CI.
Several rules are marked non-negotiable. The imported gradle/*.gradle files are deleted and modules apply the root ones instead. Dependency versions come from the grails-bom rather than being hard-coded, with dependencies.gradle used only for artifacts the BOM does not manage. Each module is added to publishedProjects in gradle/publish-root-config.gradle and uses the monorepo's publish-config.gradle, and the imported developer list is merged, alphabetized by handle, into PublishPlugin.groovy.
The earlier Spring Security merge, found in git history under commits titled Spring Security Merge, serves as the worked example, and any single step can be inspected with git show.
7 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 4deae57. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
gitFrom the folder's file list and the shell code blocks in SKILL.md.
Links to these hosts (documentation or services it may open):
apache.orgFrom URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
opencode, claude, grok, gemini, copilot, cursor, windsurf
From compatibility in the SKILL.md frontmatter.
Grails Plugin Monorepo Merge loads about 6.8k tokens when it runs. Until then it costs about 77 tokens; SKILL.md has 3,057 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from apache/grails-core at commit 4deae57, republished under its Apache-2.0 licence (© apache). 3,057 words, ~6,846 tokens.
.claude/skills/mono-repo-integration/SKILL.md (or your agent's skills folder).<!--
SPDX-License-Identifier: Apache-2.0
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
grails-<name>/) into the grails-core monorepo build.This skill is the generalization of the Spring Security merge (git commits prefixed Spring Security Merge - ..., starting at 6d06f6c84f / fd1939a7e2). When in doubt, read those commits — they are the canonical worked example:
git log --oneline --grep "Spring Security Merge"
git show <sha> # inspect any individual stepgradle/*.gradle (test-config, publish-config, java-config, docs-config, reproducible-config, rat-root-config, examples-config, etc.). Delete them all. Every module must apply from: the monorepo's existing root gradle/*.gradle files instead.grails-bom). Drop version numbers from the imported build.gradle files and from gradle.properties; rely on platform("org.apache.grails:grails-bom:$grailsVersion"). Only add a version to dependencies.gradle (and reference it) if the dependency is genuinely not already managed by a BOM. Check first: grep -i '<artifact>' dependencies.gradle grails-bom/*/build/*-constraints.adoc.publishedProjects in gradle/publish-root-config.gradle, and have each module apply from: '<root>/gradle/publish-config.gradle' (the monorepo's, not the imported one). Do not keep a per-repo publish-config.build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/PublishPlugin.groovy, keeping each list alphabetized by handle. Two rules:PublishPlugin.groovy — founder(...), developer(...), contributor(...), and emeritus(...) — and match on the person, not just the handle (e.g. christianoestreich may already be present as ctoestreich; ldaley as alkemist; graemerocher is a founder; sbglasius/matrei are active developers; burtbeckwith/puneetbehl/pledbrook/marcpalmer/jeffscottbrown are emeritus). Never add someone already in any list under any handle.emeritus. Check each author's most recent commit (git log --all --author="<name>" --format=%ad --date=short -1). If they have not contributed recently, add them as emeritus(...), not contributor(...). Most authors from a long-dormant imported plugin will be emeritus. Only use contributor(...) for genuinely active contributors.grails-test-examples/. Move the imported repo's examples/* and *-test-app projects out of the plugin folder into grails-test-examples/<name>/... and wire them through gradle/functional-test-config.gradle.grails-doc/src/en/guide/... as AsciiDoc. There is no standalone docs subproject. Markdown READMEs must be converted to .adoc.history.adoc, authors.adoc, previouswork.adoc, changelog tables, and README "release history" sections.grails-doc/build.gradle attribute map).CLAUDE.md rules throughout: jakarta.* not javax.*, Apache license header on every new file, 4-space indent, no wildcard imports, tests via public APIs.project(':grails-...'). The grails-test-examples/ apps depend on those same modules via Maven coordinates ('org.apache.grails:grails-...'), consuming them as published artifacts. Do not mix these up — convert the imported project(...) references in example/test apps to coordinates during Phase 4.Mirror the Spring Security commit sequence. Make one focused commit per phase, messaged <Name> Merge - <step>.
Bring the standalone repo in under a top-level grails-<name>/ prefix using a subtree-style merge, so the imported commit history is preserved (joined via -s ours) while the working tree is populated from read-tree. Add the source repo as a remote first (git remote add grails-<name> <url> && git fetch grails-<name>), then:
# <ref> is the imported repo's release branch, e.g. grails-redis/5.0.x
git merge -s ours --no-commit --allow-unrelated-histories grails-<name>/<ref>
git read-tree --prefix=grails-<name>/ -u grails-<name>/<ref>
git commit -m "Initial import of Grails <Name> Repository"This produces the single Initial import of Grails <Name> Repository commit (the starting point the rest of this skill restructures). Example actually used for redis:
git merge -s ours --no-commit --allow-unrelated-histories grails-redis/5.0.x
git read-tree --prefix=grails-redis/ -u grails-redis/5.0.x
git commit -m "Initial import of Grails Redis Repository"git log --oneline | grep -i "Initial import" to find the import commit.find grails-<name> -type d. Identify: plugin module(s), example/test apps, docs (adoc or README), the developer list (gradle/publish-config.gradle → it.developers), and all standalone infra.ls gradle/, publishedProjects in gradle/publish-root-config.gradle, the contributor(...) block in PublishPlugin.groovy, the guide layout under grails-doc/src/en/guide/, and the CI test-filter flags in DEVELOPMENT.md.Do not blindly delete. Most of the imported repo's standalone infrastructure is removed because the monorepo already provides it — but several files carry repo-specific customizations that must be carried over into the monorepo's equivalents first. Examine each, decide port-or-delete, then delete the standalone copy. git diff the imported file against the monorepo's equivalent to see exactly what is custom.
Examine and port (customizations must survive):
NOTICE / LICENSE — first determine whether they are standard (boilerplate Apache header/notice) or customized. If standard, just delete them: the monorepo's shared gradle plugins (applied to every module) generate/import the generic LICENSE/NOTICE automatically, so no carry-over is needed. Only when they are customized (bundled third-party components, extra attribution clauses) do you diff against the monorepo's top-level NOTICE/LICENSE and licenses/ and merge the repo-specific additions in before deleting the imported copies..gitignore — may contain custom excludes (generated dirs, plugin-specific artifacts). Fold any non-duplicate entries into the monorepo's root .gitignore before deleting.gradle/rat-*.gradle) — almost always lists files that must be excluded for rat license validation to pass (templates, generated files, third-party-licensed assets shipped with the plugin). Port every still-relevant exclude into the root gradle/rat-root-config.gradle (paths rewritten to the new grails-<name>/... location). Missing these causes ./gradlew rat to fail later. (Cross-reference Phase 2.)gradle.properties — versions should generally match the monorepo, but watch for third-party libraries pinned here that should be BOM-managed: those must be imported into the BOM (dependencies.gradle / grails-bom) rather than carried as loose properties. Carry over only genuinely non-BOM-managed props (Phase 2)..github/workflows/ — never blindly delete these. The monorepo has its own CI, but the imported workflows almost always encode test coverage that must be reproduced exactly. Before deleting, enumerate everything each job does and confirm the monorepo job you add in Phase 2 covers the same level of testing — not a single reduced run. In particular capture: (a) test matrices / config variants — e.g. grails-spring-security ran its functional tests across a 9-value -DTESTCONFIG= matrix (static, annotation, requestmap, basic, basicCacheUsers, misc, putWithParams, bcrypt, issue503); the specs are gated with @IgnoreIf({ System.getProperty('TESTCONFIG') != '<config>' }), so a single run silently skips 8/9 configs and looks green while covering almost nothing. Every matrix axis (config, JVM version, container version, DB flavor) must be reproduced. (b) required service containers (a redis/postgres the functional tests need — prefer Testcontainers per Phase 2). (c) extra validations / dependency-setup steps. Write down each axis and value here, then reproduce them in the Phase 2 job. When in doubt, diff the imported job step-by-step against the monorepo job and account for every flag.buildSrc/ — usually removable, but inspect for custom tasks/plugins/conventions the build actually depends on; integrate any such behavior into build-logic/ or the root gradle config before deleting.Examine briefly, then typically delete:
etc/ — typically build-verification/release scripts (reproducible-build checks, artifact verification). Usually safe to drop, but do a short scan to confirm nothing the monorepo lacks is referenced by the build..asf.yaml, .sdkmanrc, CODE_OF_CONDUCT.md, HEADER, ISSUE_TEMPLATE.md — standalone-repo metadata superseded by the monorepo's; delete.Delete outright (always superseded by the monorepo):
gradlew, gradlew.bat, gradle/wrapper/, gradle-bootstrap/settings.gradle, root build.gradlegradle/*.gradle convention files (test-config, publish-config, java-config, docs-config, reproducible-config, examples-config, and the now-ported rat config)README.md — its content is migrated to the guide in Phase 3, then deleted.Test-skip property note: the monorepo's grails-core CI workflows pass a skip flag (e.g. -Pskip<Name>/-Pskip<Name>Tests) to exclude this plugin's functional tests from the default runs, and a separate dedicated workflow runs them (with any required service containers). Note here what the imported CI needed; wire the flag + dedicated job in Phase 2.
Restructure directories to the monorepo convention. Initial Moves is pure deletion + relocation — do NOT rewrite file contents here. Keeping moves and content edits in separate commits means git records relocations as renames, so every later phase's content change diffs cleanly against the moved file instead of appearing as a delete+add. Concretely, the Initial Moves commit:
grails-<name>/plugin/{grails-app,src,build.gradle} to grails-<name>/ so the plugin project's dir is simply grails-<name>/ (no projectDir mapping needed, since the dir name matches the project name). Multi-module repos (like spring-security) keep nested plugin/docs folders.grails-test-examples/<name>/... (e.g. grails-<name>/examples/<app> → grails-test-examples/<name>/<app>), moved verbatim. If the repo has only a single functional app, flatten it directly into grails-test-examples/<name>/ (drop the redundant per-app subfolder) and name the project grails-test-examples-<name>.
Each deployable module gets a clean folder; nested project dirs are mapped explicitly via projectDir in settings.gradle, so directory names can differ from project names. The content edits to these moved files (build-script rewrites, dependency-by-coordinate conversion, applying root gradle config) happen in the later phases and will show as clean diffs.Edit, in this order:
settings.gradle (root): add each module to the include(...) list with a grails-<name>-... project name, then set project(':grails-<name>-...').projectDir = new File(settingsDir, 'grails-<name>/<path>'). Add functional/example apps as grails-test-examples-<name>-... mapped into grails-test-examples/<name>/....build.gradle: keep the plugins { ... } block and dependencies, but (a) strip versions in favor of the BOM, (b) replace the apply { from ... } block to point at the root gradle/*.gradle files. Declare all Gradle plugins in the plugins { } block (the composite build resolves the project's org.apache.grails.* convention plugins there) rather than the legacy apply plugin: '...' form — match the modern test projects (e.g. grails-test-examples/scaffolding). Note: apply from: '<script>.gradle' for applying gradle script snippets is a separate, still-standard mechanism — only plugin application moves into plugins { }. (test-config.gradle, publish-config.gradle, docs-config.gradle, java-config.gradle, reproducible-config.gradle, etc.). Delete the module's reference to any deleted per-repo gradle file. For dependencies on other monorepo modules, use project(':grails-...') syntax (not Maven coordinates) — these are the published Gradle projects building alongside this one (see Principle 10).org.grails.plugins:grails-<name>); under the ASF it becomes org.apache.grails:grails-<name>. In the plugin build.gradle, set group = 'org.apache.grails' (and drop any standalone grailsPublish { ... } block — the monorepo's buildsrc.publish convention plugin supplies the POM metadata). Register the rename in BOTH places that track it: add a row to RENAME.md (the documented old→new mapping table) and a per-repo <name>_mappings block to etc/bin/rename_gradle_artifacts.sh (mirroring the redis_mappings block), so the coordinate migration is recorded and the sed-based rewrite script stays complete. Update install/usage snippets in the migrated docs to the new coordinates too.dependencies.gradle: add only the genuinely-unmanaged dependency coordinates + versions (alphabetical, in both bomDependencyVersions and bomDependencies).gradle.properties: add only non-BOM-managed version props; match the existing <name>Version naming style.gradle/publish-root-config.gradle: add every published module to publishedProjects (alphabetical).build-logic/plugins/.../PublishPlugin.groovy: merge in the imported developers (alphabetical, deduped against both lists). Per Principle 4, check each author's commit recency and add inactive ones as emeritus('<id>', '<name>', project) rather than contributor(...).only<Name>Tests / skip<Name>Tests consistently across: gradle/test-config.gradle, gradle/functional-test-config.gradle, gradle/grails-data-tck-config.gradle, build-logic/docs-core/build.gradle, and document both in DEVELOPMENT.md. (Spring Security added onlySpringSecurityTests/skipSpringSecurityTests.) Only introduce a dedicated <name>-test-config.gradle if the plugin truly needs bespoke test wiring (Spring Security did for Geb/integration); prefer reusing the shared one.gradle/rat-root-config.gradle: add RAT excludes for template files, generated files, and third-party-licensed assets the module ships..github/workflows/gradle.yml: add a CI job (or extend an existing matrix) that runs the new only<Name>Tests slice. Reproduce every test matrix / config variant the imported CI ran (the axes you recorded in Phase 1) — do not collapse a multi-config matrix into one run. If a matrix variant only affects a single example app (e.g. the Spring Security TESTCONFIG variants only change the core functional-test-app), give it its own dedicated matrix job scoped to that project (./gradlew :grails-test-examples-...-functional-test-app:check -DTESTCONFIG=${{ matrix.test-config }} -PgebAtCheckWaiting) rather than re-running the whole only<Name>Tests slice per variant — this matches how the standalone repo split its coreTests and functionalTests jobs, and avoids re-running unrelated apps N times. For tests that need an external service (DB, cache, broker), prefer Testcontainers driven by a Spock IGlobalExtension over a GitHub Actions services: container — this is the repo's established convention (see the mongodb example apps' SpringBootStart*Extension/*ContainerVersion pattern; the monorepo has no services: blocks). Check the BOM first — the container module is often already managed (e.g. com.redis:testcontainers-redis, org.testcontainers:*). The extension starts the container, reads the image version from a -P<name>ContainerVersion system property (wired through the test-config), and injects host/port into the spec (the imported tests usually already read host/port from env/config). Run the CI job with -Ponly<Name>Tests -P<name>ContainerVersion=<v> across a version matrix. Also pass -Pskip<Name>Tests on the plain ./gradlew build(-with-tests) jobs so the service-dependent tests don't run where no container is provisioned.publish job's needs: list and its if: result guard ((needs.<job>.result == 'success' || needs.<job>.result == 'skipped')) in gradle.yml. Otherwise the snapshot publish runs even when the plugin's tests fail — the tests exist but don't protect anything. After adding a job, grep the publish (and any other publishing) job's needs/if and confirm your new job id is present in both.grails-doc/src/en/guide/toc.yml, NOT by index.adoc's include:: directives. DocPublisher builds the guide from toc.yml (it throws "Legacy TOC is no longer supported" if absent). You MUST add your chapter there or it will not render — editing index.adoc alone does nothing. Format: a top-level key: is a chapter mapped to <key>.adoc; title: sets the heading; child key: Title entries map to <chapter>/<key>.adoc. Section keys must be globally UNIQUE across the entire guide (the publisher errors with "Duplicate section name" otherwise) and the key doubles as the filename — follow the springSecurityCore convention (fully-qualified unique keys like redisInstallation, not generic installation which collides with other chapters). Internal headings inside a section file start at ==== (level 4), matching existing files like services.adoc. (Keep index.adoc in sync too if the repo maintains it, but toc.yml is what the build reads.)docs/, no .adoc guide), the docs are typically living in the project's README.md. In that case convert the README.md into an appropriate guide section rather than skipping documentation. Strip README-only boilerplate (build/CI badges, "Building"/"Publishing to mavenLocal" dev instructions, release history) and keep the user-facing usage content.grails-doc/src/en/guide/<area>/<name>/...adoc. For plugins with a security flavor this is grails-doc/src/en/guide/security/securityPlugins/...; otherwise pick the matching guide area (or a new top-level area for the plugin). Convert Markdown READMEs to AsciiDoc.grails-doc/src/en/guide/index.adoc and the relevant section .adoc).grails-doc/build.gradle (sourcedir/functionalSourceDir-style attribute map) and point them at the relocated grails-test-examples/<name>/... apps.grails-doc/build.gradle rather than hard-coding it per page.The apps were physically moved to grails-test-examples/<name>/... back in Initial Moves; this phase is the content edits on them:
build.gradle to depend on the plugin by Maven coordinates (e.g. implementation 'org.apache.grails:grails-<name>'), not project(':grails-<name>') — grails-test-examples apps consume modules as published artifacts, the opposite convention from the plugin modules themselves (see Principle 10). Use the BOM, and apply from: the root gradle/functional-test-config.gradle / gradle/test-config.gradle (or the dedicated <name>-test-config.gradle).settings.gradle mappings (Phase 2) and that functional-test-config.gradle recognizes the grails-test-examples-<name>-* prefix for the test-filter flags.xxxVersion).codeStyle (wildcard imports, tabs, if(, unnecessary GStrings/semicolons, brace spacing, missing trailing newline, class-starts-with-blank-line). Fix mechanically until :grails-<name>:codenarcMain passes; test-example apps don't apply grails-code-style, so they aren't style-checked.cyclonedxBom): a merged plugin pulls transitives the SBOM plugin can't auto-resolve a license for, failing with "Could not determine License id for dependency: …". Trace it (./gradlew :grails-<name>:dependencyInsight --dependency <group:artifact> --configuration runtimeClasspath) to confirm what pulls it and that the license is ASF-acceptable, then add a mapping to LICENSE_MAPPING (and a LICENSES entry if the license has no SPDX id) in build-logic/plugins/.../SbomPlugin.groovy — the same place jline/sitemesh are mapped. (Redis: org.json:json via jedis, relicensed to Public Domain → mapped.)bin//build/ artifacts that rat flags; filter the report to your new files (excluding build//bin/) to confirm the contribution itself is clean.rat flags them. Add headers with the per-filetype scripts in etc/bin/ — add-license-groovy-java.groovy, add-license-gsp.groovy, add-license-css.groovy, add-license-js.groovy, add-license-yml.groovy, add-license-properties.groovy, etc. — each takes a target path and recurses (skipping files that already have the marker): groovy etc/bin/add-license-<type>.groovy grails-test-examples/<name>. There is no add-license-xml; add the XML comment header (e.g. to logback-spring.xml/logback-test.xml) by hand, matching an existing example app's format.~/.gradle; signing needs the 1Password agent) — run every ./gradlew with the sandbox disabled, and export GRADLE_OPTS="-Dorg.gradle.jvmargs=-Xmx4G"../gradlew build -PskipTests # compiles + wires
./gradlew :grails-<name>:test
./gradlew check -Ponly<Name>Tests --continue # the new test slice
./gradlew codeStyle
./gradlew rat # license headers / excludes
./gradlew :grails-doc:publishGuide -x aggregateGroovydoc # docs buildgrails-<name>/gradle/*.gradle, buildSrc/, gradlew*, .github/, .asf.yaml, gradle-bootstrap/, repo-root settings.gradle/build.gradle/gradle.properties remain.dependencies.gradle/gradle.properties.publishedProjects; authors merged into PublishPlugin.groovy.only<Name>Tests/skip<Name>Tests flags exist in all test-config files + DEVELOPMENT.md; CI job added.TESTCONFIG matrix); the imported workflows were audited before deletion, not blindly removed.publish job's needs: and its if: result guard, so publishing is blocked when the new tests fail.grails-test-examples/<name>/ and depend on the in-repo project.grails-doc/src/en/guide/..., wired into the TOC, no release history/authors, no hard-coded legacy URLs, BOM-style install snippets../gradlew build -PskipTests, codeStyle, rat, and the doc build all pass.© apache, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in .agents/skills/mono-repo-integration of apache/grails-core.
Open the folder on GitHubat commit 4deae57
Grails Plugin Monorepo Merge next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Grails Plugin Monorepo Merge this skillapache/grails-core | 2.9k | — | ~6.8k | Automated safety check: Pass | Apache-2.0 | |
| Migrate Internal Package into GhostTryGhost/Ghost | 55k | — | ~3.8k | Automated safety check: Pass | MIT | |
| Project Gradle Third Party Version UpgradeafkT/DevUtils | 1.6k | — | ~1.2k | Automated safety check: Pass | Apache-2.0 | |
| Play Billing Library Version Upgradearindamxd/camerax-android | 132 | 5 repos | ~1.4k | Automated safety check: Pass | Apache-2.0 | |
| Hz API Upgrademeta-quest/agentic-tools | 213 | — | ~1.8k | Automated safety check: Pass | Apache-2.0 | |
| Typescript Tooling MigrationArize-ai/phoenix | 12k | — | ~2.8k | Automated safety check: Pass | Apache-2.0 |
TryGhost/Ghost
Moves a package from another TryGhost repository into Ghost as an internal workspace package while keeping its Git history, with checkpoints for the steps that need an administrator.
afkT/DevUtils
对 DevUtils 工程(DEPSROOT=file/gradle、DEPSMANIFEST=file/deps)中定义的第三方库 GAV 依赖做版本查证与升级;结合 Maven Central、Google Maven、Gradle Plugin Portal、 JitPack 与 GitHub Releases/README 交叉校验「最新可用版本」;必要时修正…
arindamxd/camerax-android
A skill your agent uses when upgrading or migrating an Android project from any legacy Google Play Billing Library (PBL) version to the latest stable version of PBL.
meta-quest/agentic-tools
Upgrades Meta VR apps to newer Horizon OS SDK versions — migration guides, deprecated API replacements, changelog.
Arize-ai/phoenix
Migrate or upgrade TypeScript tooling in the Phoenix monorepo.
neo4j-contrib/neo4j-skills
Neo4j Java Driver v6 — driver lifecycle, Maven/Gradle setup, executableQuery, executeRead/Write managed transactions, explicit transactions, async/reactive patterns, error handling, data type…
apache/grails-core
Guides building Grails web applications and REST APIs with GORM, controllers, services, views, plugins and Spock and Geb testing.
apache/grails-core
Guidance for Groovy 5 work in Grails projects: syntax, closures, traits, DSLs, metaprogramming, Spock tests, static compilation and Java 21 integration.
apache/grails-core
Guides changes to the grails-data-hibernate7 module, covering domain binding, Hibernate 5 to 7 migration work, generators and integration specs.
apache/grails-core
Guide for writing modern Java 21 in a Grails and Groovy codebase: records, sealed classes, pattern matching, text blocks and how Java works alongside Groovy.
apache/grails-core
Guides running, reviewing and fixing test failures across grails-core modules with Gradle, including targeted runs and the aggregate HTML and Markdown reports.
apache/grails-core
Guide to running, reading and fixing code style and analysis violations in grails-core with CodeNarc, Checkstyle, PMD, SpotBugs, Spotless and JaCoCo through Gradle.
Works with
Categories
Guides merging a standalone Grails plugin repository into the grails-core monorepo as Gradle subprojects that use the shared build, publishing, docs and CI. This skill describes a repeatable process for folding a plugin repository that used to live on its own, such as grails-spring-security or grails-redis, into the grails-core monorepo. The plugin's source is first copied into a top-level folder, then its own build, release and CI machinery is stripped out and each module is rewired onto the monorepo's shared Gradle configuration, publishing setup, documentation guide and CI.
Grails Plugin Monorepo Merge fits situations like: moving a standalone Grails plugin repository into the grails-core monorepo; replacing an imported plugin's own Gradle, publish and CI files with the shared ones; registering newly merged modules for publishing and the documentation guide; cleaning hard-coded dependency versions out of an imported build.
Run `npx skills add apache/grails-core --skill mono-repo-integration -a claude-code`. Or copy the skill folder (.agents/skills/mono-repo-integration in apache/grails-core) into .claude/skills/mono-repo-integration in your project. Claude Code loads it when a task matches its description.
Run `npx skills add apache/grails-core --skill mono-repo-integration -a codex`. Or copy the skill folder (.agents/skills/mono-repo-integration in apache/grails-core) into .agents/skills/mono-repo-integration in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add apache/grails-core --skill mono-repo-integration -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/mono-repo-integration, .gemini/skills/mono-repo-integration, .github/skills/mono-repo-integration and .opencode/skills/mono-repo-integration in your project.
Going by SKILL.md and its folder, Grails Plugin Monorepo Merge needs the command-line tools its instructions call (git). Our summary lists: A grails-core checkout with the plugin source already copied into a top-level folder; Gradle. Compatibility (from SKILL.md): opencode, claude, grok, gemini, copilot, cursor, windsurf.
SKILL.md names 1 domain. As links in the text: apache.org. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Grails Plugin Monorepo Merge is published under the Apache-2.0 licence (declared in SKILL.md). It allows redistribution, so the full SKILL.md is shown on this page.
About 6.8k tokens (SKILL.md is roughly 27k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Grails Plugin Monorepo Merge: Migrate Internal Package into Ghost (TryGhost/Ghost, 55k stars), Project Gradle Third Party Version Upgrade (afkT/DevUtils, 1.6k stars), Play Billing Library Version Upgrade (arindamxd/camerax-android, 132 stars) and Hz API Upgrade (meta-quest/agentic-tools, 213 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
apache (a GitHub organization) maintains it in apache/grails-core, which has 2,934 GitHub stars. The repository holds 9 skills in this directory. The repository was last updated on October 8, 2026.
Source: apache/grails-core on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.