sunchayn/fresh-package
Fresh Package from sunchayn gives Laravel developers a clean, opinionated starting point for building reusable PHP packages, with sensible defaults and an Artisan-friendly workflow that cuts boilerplate and helps maintainable components ship faster.
This is a template, not a dependency. There is no composer require sunchayn/fresh-package in your future. Create the repo from the GitHub "Use this template" button (or clone and delete .git, then re-init). Everything the skeleton emits is your code from commit one — nothing from upstream ships into production.
Read composer.json before you read any source. It is the contract for the rest of the skeleton:
name / description / keywords — the metadata you'll forget to changepsr-4 autoload map — this decides your namespace and therefore every use line you will ever write in the packagescripts block — this is how you run tests, static analysis, Rector, and the sandbox. Learn the script names; don't retype vendor/bin/... by hand, because the sandbox invocation is non-obviousextra.laravel.providers — package discovery wiringThen read, in this order: the service provider in src/, the config file, tests/, workbench/, and skills/skeleton/SKILL.md.
Do the placeholder sweep as one deliberate sitting. Markers like :package_name, :vendor_slug, and :package_slug are spread across composer.json, namespaces, class names, config keys, publish tags, README, and SKILL.md. Resist days of ad-hoc find-and-replace — the half-renamed skeleton is the classic way to lose an afternoon, and v0.4.0's "broken structure after marker cleanup" fix exists precisely because of it. After the sweep: composer dump-autoload, then run the full suite including static analysis.
Your first use case should be deliberately boring. A backend-only package that merges one config file, binds one class in the provider, and has one passing test running inside the sandbox. Get to green before writing feature code. Time-to-first-green-test is the entire product; if you're still fighting the harness on day two, the rename pass went wrong, not the skeleton.
Defer backend-only vs. full-stack. Both are supported from one starting point, so don't pre-build view namespaces, publishable assets, and frontend config for a package that may never need a blade.
Scaffold → rename → green → feature. This sequence is fixed. Every deviation (feature-first in a fresh skeleton, "I'll fix the namespace later") costs more than it saves.
Two-repo posture — the important one. Treat upstream as a source of ideas, and maintain an internal golden template as the thing your team actually scaffolds from. Bake in your CI, license headers, coding standard, and registry settings once, in the golden template. Daily development then happens in generated packages, which are ordinary Laravel packages. Periodically diff the golden template against a pinned upstream tag and cherry-pick. Fork-and-pin, not track-loose.
Keep the service provider thin and make it the single seam. Discovery, mergeConfigFrom, publish tags, and bindings live there; behavior lives in dedicated classes. This keeps "what does installing this package do to the host app?" answerable by reading one file — which is the question you'll actually get asked in review.
Config is the documented public surface. Pair mergeConfigFrom (safe defaults) with a publishable tag (overrides). Downstream developers read the config file before the README, so give it the same care.
Live in the workbench/sandbox, not a throwaway test app. The sandbox is a real Laravel app skeleton the package is exercised inside — make it your default dev loop and the home of your integration tests. v0.4.0 added parallel sandbox runs, so concurrent/long test runs are supported; lean on it.
Static analysis and Rector belong in the inner loop. Run them locally before pushing so CI is a confirmation, not a surprise. Put Rector output in its own commit — mixing automated refactors into a feature diff makes review useless and makes the next rebase against upstream painful.
Treat SKILL.md as part of definition of done. It's adopter-facing integration guidance for downstream consumers and their coding agents, deliberately scoped to the public API. Update it in the same PR that changes the public API. Even if you later abandon the skeleton, copy this convention — machine-readable integration guidance next to the README is cheap and high-leverage. Follow the template's own rule: document adoption, not internals.
Grow into full-stack. Add view namespace registration, publishable assets, and frontend config only when the package genuinely has a surface.
If you layer your own generator on top, note v0.4.0's "safe mode for chisel-extended" — the skeleton is designed to be extended by other tooling. Write your internal scaffolder to be non-destructive and idempotent; that's the posture upstream is signaling.
Template drift is the risk, not runtime risk. There's no runtime surface and effectively no switching cost — but teams fork, customize, and diverge until the standardization payoff evaporates. Mitigate with a named internal owner, a pinned version, and a small upstream diff. Record the pinned version and the reason for adoption in the generated repo, not in someone's head.
There is no propagation mechanism from upstream to already-generated packages. The upgrade path is manual diff, selective cherry-pick, or regenerate. That's acceptable, but it means Laravel major upgrades are a scheduled review activity rather than something CI surfaces for you.
Placeholder cleanup is where skeletons break. Markers hide in namespaces, class names, config keys, publish tag strings, README, and SKILL.md. Rename atomically, then immediately run tests and static analysis — a mismatched namespace often fails at autoload time and stays silent until the sandbox boots.
Two failure modes, two checks. Package not discovered in the sandbox → verify the extra.laravel.providers entry and re-run composer dump-autoload after the rename. Config not publishing → verify the publish tag name and the mergeConfigFrom path agree. Both are rename casualties far more often than skeleton bugs.
"Opinionated" is not marketing. Folder structure, test sandbox, static analysis, and conventions are all prescribed. This is a conventions decision, not a tooling decision — get team buy-in before package #1, not after package #3 when everyone has quietly diverged.
Pre-1.0, single maintainer, ~33 stars, no SLA or deprecation policy. Assume you own your fork. That's fine because the downside is bounded, but don't plan around upstream responsiveness.
Don't read the zero-dependents number literally. Scaffolding repos are cloned, not required, so dependent counts structurally understate usage. Treat low visibility as a bus-factor consideration, not a quality verdict.
Verify the v0.4.0 release timestamp against the actual repository state before citing it as momentum or pinning to it — it appears future-dated.
The README is intentionally decluttered (reduced further in v0.4.0). Expect to read source and commit history. Bookmark the service provider, composer.json, and the test bootstrap — those three answer most "how does this work?" questions.
Don't migrate mature packages into this layout. Use it for greenfield; selectively adopt the structure, Composer scripts, static-analysis config, and sandbox pattern in existing packages. A forced rewrite of a stable package is pure churn.
Extension points, ordered by safety: Composer scripts (customize freely — CI, linting, registry steps live here), config file and publish tags (safe to reshape), service provider (keep additions additive), directory structure (last resort — deep structural forks make future rebases expensive).
How can I help you explore Laravel packages today?