This monorepo treats each package as a first-class split package.
Use this checklist when adding a new package.
This is the sequence that actually works.
Create the package directory under packages/<name> with:
src/tests/composer.jsonREADME.mdCHEATSHEET.mddocs/
For docs, keep the initial structure small:
docs/_meta.yamldocs/overview.mddocs/quickstart.md
The package must have a valid composer.json before it can be published to Packagist.
Add the package to packages.json:
{
"local": "packages/http-pool",
"repo": "cognesy/instructor-http-pool",
"github_name": "instructor-http-pool",
"composer_name": "cognesy/instructor-http-pool"
}Then update:
- root
composer.jsonautoload and autoload-dev - root
README.md - CONTENTS.md
- CONTRIBUTING.md
- any docs registries under
packages/*/resources/config/docs.yamlor.yml - docs landing pages if the package should appear there
- examples/docs pointers if this package splits functionality out of another package
If the package adds public docs, give it:
- a description in each docs config
- a stable place in package order
Run:
./scripts/update-split-yml.sh .This regenerates the package matrix in .github/workflows/split.yml from packages.json.
Do not edit the split matrix by hand unless the generator is broken.
Create the split repository with gh:
gh repo create cognesy/instructor-http-pool \
--public \
--description "Concurrent HTTP request execution for Instructor"Verify it exists:
gh repo view cognesy/instructor-http-pool --json name,url,visibilityPackagist will reject a new repo if main does not contain composer.json.
Before submitting to Packagist:
- push the monorepo changes that introduce the package, then let the split workflow publish it
- or bootstrap the split repo manually with the package contents if you need it immediately
The important check is:
gh repo view cognesy/instructor-http-pool --webThen confirm the repo main branch already contains:
composer.jsonsrc/README.md
Preferred path in this repo: Packagist API token from .env.
PACKAGIST_API_USERNAME=$(sed -n "s/^PACKAGIST_API_USERNAME='\\(.*\\)'$/\\1/p" .env)
PACKAGIST_API_TOKEN=$(sed -n "s/^PACKAGIST_API_TOKEN='\\(.*\\)'$/\\1/p" .env)
curl -X POST \
-H 'content-type: application/json' \
"https://packagist.org/api/create-package?username=${PACKAGIST_API_USERNAME}&apiToken=${PACKAGIST_API_TOKEN}" \
-d '{"repository":{"url":"https://github.com/cognesy/instructor-http-pool"}}'Expected response:
{"status":"success"}Then verify:
curl -I https://packagist.org/packages/cognesy/instructor-http-pool
curl -I https://repo.packagist.org/p2/cognesy/instructor-http-pool.jsonManual fallback:
- Open
https://packagist.org/packages/submit - Submit the split repository URL
- Confirm the package name from
composer.json - Enable the GitHub hook or auto-update
Check:
- docs autodiscovery sees
packages/<name>/docs - split workflow contains the package
- root Composer autoload includes the namespace
- package
composer.jsonis valid - Packagist can resolve the package
- the split repository exists and is public
Useful checks:
composer validate packages/http-pool/composer.json
rg "http-pool" packages.json .github/workflows/split.yml packages/*/resources/config
gh repo view cognesy/instructor-http-pool --json url,defaultBranchRefAt minimum:
composer validate packages/http-pool/composer.json
php vendor/bin/pest packages/http-pool/testsIf the package changes shared infrastructure, also run:
composer testpackages.jsonis the source of truth for split-package registration.update-split-yml.shshould be used instead of editing.github/workflows/split.ymlby hand.- Packagist submission depends on the split repo, not the monorepo. If the split repo is empty, submission fails.
- Keep package docs minimal at first. Add more only when the API stabilizes.