grafite/blacksmith
Grafite's Blacksmith is a Laravel scaffolding package that forges CRUD code from your database schema, generating models, controllers, routes, and views so you can quickly build admin panels and backend prototypes with less boilerplate.
Day one: confirm what the package actually is. The metadata is contradictory — the package description advertises a schema-driven CRUD scaffolder ("point it at a table, get model/controller/routes/views"), while the operating assessments describe a thin Forge rebuild trigger. Resolve this before you write a line of integration code:
composer require grafite/blacksmith
php artisan vendor:publish --provider="Grafite\Blacksmith\BlacksmithServiceProvider"
php artisan list | grep -i black
cat vendor/grafite/blacksmith/composer.json # check PHP/Laravel constraints and license
ls vendor/grafite/blacksmith/src # read the service provider first
The service provider's register()/boot() tells you which of the two packages you actually installed: a commands([...]) array of rebuild commands, or generator commands plus view/config stubs. Everything downstream depends on this answer.
If it's the rebuild tool (the day-to-day use case):
config/blacksmith.php. It is the source of truth for the Forge API token, server ID, site ID, and the rebuild step list. Grab the IDs from the Forge URL: forge.laravel.com/servers/{server}/sites/{site}..env immediately so staging and production don't share a token:BLACKSMITH_FORGE_TOKEN=...
BLACKSMITH_SERVER_ID=123456
BLACKSMITH_SITE_ID=789012
forge, and run the command exactly as the deploy script will:sudo -u forge php artisan blacksmith:rebuild # verify the real name via `artisan list`
If it's the CRUD scaffolder: run the generator against a single throwaway table first, diff the output, and check whether generated views/controllers match your conventions before generating anything you intend to keep.
First real use case: replace a hand-maintained Forge deploy script with one artisan invocation, so composer install, migrate, cache clears, and queue restarts are identical across staging and production instead of drifting apart.
Forge deploy script integration. Keep git pull and environment-specific steps in Forge's deploy script; delegate the rebuild sequence to the package.
cd /home/forge/example.com
git pull origin main
composer install --no-dev --no-interaction
php artisan blacksmith:rebuild # confirm name from `artisan list`
Per-environment config, never hardcoded. Use distinct Forge sites for staging and production and verify what Laravel actually loaded after each deploy:
php artisan config:show blacksmith # Laravel 9+
Wrap it in your own command. Business logic belongs in your app, not in vendor/.
// app/Console/Commands/Deploy.php
public function handle(): int
{
$this->call('down'); // maintenance mode for schema changes
Artisan::call('blacksmith:rebuild'); // or inject the package's service
$this->call('up');
$this->warmCaches();
return self::SUCCESS;
}
This survives package upgrades, gives you a single entry point for pre/post hooks (Slack notify, DB snapshot, cache warm), and means a failed rebuild can restore the site instead of leaving it down.
Gate deploys on CI. Trigger the Forge webhook from GitHub Actions only after tests pass; store the webhook URL and token as repository secrets.
- name: Trigger Forge deploy
if: success()
run: curl -fsS -X POST "${{ secrets.FORGE_DEPLOY_WEBHOOK }}"
-f matters — a silent 200-on-failure is how you end up shipping a stale commit.
Testing. If the package uses Laravel's HTTP client, fake it in a feature test and assert both the exit code and the outgoing request:
Http::fake();
$this->artisan('blacksmith:rebuild')->assertExitCode(0);
Http::assertSent(fn ($req) => str_contains($req->url(), '/deploy'));
Assert exit codes explicitly; Forge's script will happily continue past a non-zero exit unless you check.
Cache re-warm as a follow-up job. If the rebuild clears caches, schedule a job that hits key routes rather than letting the first user absorb the cold start.
vendor/grafite/blacksmith/src, treat every command name, config key, and README line as unverified. artisan list and the source are the only trustworthy documentation.NOASSERTION license is a blocker, not a footnote. Clear it with legal before it touches production. If it can't be resolved, the fallback is a ~50-line internal command — cheaper to own than to inherit.composer.json, vendor or fork it, and plan to replace it. Do not adopt it as a platform dependency for a time-boxed convenience..env: php artisan config:clear locally, php artisan config:cache on the server. A stale cached Forge token produces 401s that look like Forge problems.forge. Variables exported in your SSH session are absent. Rely on the app's .env, never shell exports, and reproduce failures with sudo -u forge.composer install or migrations can exceed the limit — split them into a queued job or a separate step rather than stuffing everything into one rebuild command.forge → read storage/logs/laravel.log → compare against the Forge deploy log. Most failures are token scope, a missing config key, or a working-directory mismatch — not package bugs.How can I help you explore Laravel packages today?