Repository navigation
feat: bundle http consumer skill #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| --- | ||
| category: added | ||
| type: minor | ||
| --- | ||
|
|
||
| Bundle the fast-forward-http consumer skill with executable examples, optional installation guidance and Composer discovery metadata. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| # fast-forward-http maintenance | ||
|
|
||
| This repository owns `fast-forward/http`. Read Composer metadata, source and | ||
| tests before changing public integration. Preserve unrelated work. Run | ||
| `composer install`, `composer validate --strict` and `composer dev-tools`. | ||
| Keep merge, release and deployment decisions with the maintainer. Ordinary | ||
| source/resources share this root contract; consumer procedures live in SKILL.md. | ||
|
|
||
| ## Bundled consumer skill | ||
|
|
||
| Read [the consumer skill](resources/skills/fast-forward-http/SKILL.md) when changing application integration | ||
| examples, consumer guides or the skill. Keep its version contract, references | ||
| and executable examples aligned with the supported public API. The canonical | ||
| distributable source is `resources/skills`; it needs no installed copy or host | ||
| alias. Repository maintenance continues to follow this AGENTS.md. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| Copyright (c) 2025 Felipe Sayão Lobato Abreu | ||
|
|
||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| of this software and associated documentation files (the "Software"), to deal | ||
| in the Software without restriction, including without limitation the rights | ||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| copies of the Software, and to permit persons to whom the Software is furnished | ||
| to do so, subject to the following conditions: | ||
|
|
||
| The above copyright notice and this permission notice shall be included in all | ||
| copies or substantial portions of the Software. | ||
|
|
||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| THE SOFTWARE. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| --- | ||
| name: fast-forward-http | ||
| description: Wire Fast Forward HTTP providers into an application container and obtain PSR-17 factories and a PSR-18 client. | ||
| license: MIT; see LICENSE | ||
| compatibility: Supports fast-forward/http ^1.2 and PHP ^8.3. Requires Composer and declared extensions; inspect the installed version. Earlier releases are outside this contract. | ||
| metadata: | ||
| author: Fast Forward | ||
| api-baseline: fast-forward/http ^1.2 | ||
| --- | ||
|
|
||
| # Compose HTTP services | ||
|
|
||
| Use this skill for an application consuming `fast-forward/http:^1.2`. | ||
| Read its instructions, manifest/lockfile and installed source before editing. | ||
| Run `composer show fast-forward/http`. For versions outside this contract, | ||
| inspect matching documentation; do not silently upgrade the application. | ||
|
|
||
| ## First working integration | ||
|
|
||
| Requires PHP ^8.3, Composer's application autoloader and this package's runtime | ||
| dependencies. | ||
| With authority to install the dependency: | ||
|
|
||
| ```sh | ||
| composer require 'fast-forward/http:^1.2' | ||
| ``` | ||
|
|
||
| Create `app.php` in the application root alongside composer.json/vendor: | ||
|
|
||
| ```php | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| require __DIR__ . '/vendor/autoload.php'; | ||
|
|
||
| use FastForward\Config\ArrayConfig; | ||
| use FastForward\Container\ContainerInterface; | ||
| use FastForward\Http\ServiceProvider\HttpServiceProvider; | ||
| use Psr\Http\Client\ClientInterface; | ||
| use Psr\Http\Message\ResponseFactoryInterface; | ||
| use Psr\Http\Message\RequestFactoryInterface; | ||
| use function FastForward\Container\container; | ||
|
|
||
| $config = new ArrayConfig([ContainerInterface::class => [HttpServiceProvider::class]]); | ||
| $container = container($config); | ||
| $response = $container->get(ResponseFactoryInterface::class)->createResponse(202); | ||
| $request = $container->get(RequestFactoryInterface::class)->createRequest('GET', 'https://example.invalid/'); | ||
| $client = $container->get(ClientInterface::class); | ||
| if ($response->getStatusCode() !== 202 || $request->getMethod() !== 'GET' || !$client instanceof ClientInterface) { | ||
| throw new RuntimeException('HTTP composition failed.'); | ||
| } | ||
|
|
||
| echo "integration ready\n"; | ||
| ``` | ||
|
|
||
| Run `php app.php`. It throws on a wrong result; success prints | ||
| `integration ready`. It uses no production data and starts no server. | ||
|
|
||
| ## Wiring and failure boundaries | ||
|
|
||
| Store the raw provider list under `FastForward\Container\ContainerInterface::class`; the ConfigContainer exposes this as `config.FastForward\Container\ContainerInterface`. Pass the configuration to `container($config)`, then pass the returned container to the application's runtime. The provider composes HttpMessageFactoryServiceProvider and HttpClientServiceProvider. It supplies client/factories and a globals-based server request, not an HTTP server, route dispatcher or response emitter. | ||
|
|
||
| Without application configuration use `container(HttpServiceProvider::class)`. Resolve the extended `FastForward\Http\Message\Factory\ResponseFactoryInterface` for payload helpers, and the PSR ResponseFactoryInterface for ordinary PSR-17 creation. They are distinct services. | ||
|
|
||
| Put a custom ArrayServiceProvider before defaults to override an interface. The first source that successfully resolves the id wins; service-provider products are cached. Request/response factory calls create message objects, while resolving the globals-based ServerRequestInterface service can cache the request: build a fresh request explicitly for long-lived worker iterations. Missing services raise PSR-11 not-found errors; non-PSR factory failures propagate. Do not send the example.invalid request; it tests composition without a network dependency. | ||
|
|
||
| The helper tries aggregate sources in registration order. A PSR container or | ||
| not-found exception from one source permits fallback to another source; other | ||
| throwables propagate. Source priority is therefore the first successful resolution, | ||
| not a guarantee that an earlier broken factory terminates lookup. Nested provider | ||
| list errors during helper composition are caught; if services are absent, inspect | ||
| the raw configuration and resolve the provider directly to diagnose the failure. | ||
|
|
||
| ## Verify integration | ||
|
|
||
| Run the [complete example](examples/integration.php) against the application's | ||
| autoloader in a disposable process. It checks success and negative cases: | ||
|
|
||
| ```sh | ||
| php /path/to/fast-forward-http/examples/integration.php ./vendor/autoload.php | ||
| ``` | ||
|
|
||
| Expected final marker: `fast-forward-http: ok`. Keep application-specific regression | ||
| tests in its existing PHPUnit suite, with each fixture class in its same-named | ||
| file. File copying, host discovery and completed agent tasks are different checks. | ||
| For optional copying/synchronization load | ||
| [installation and lifecycle](references/installation.md). |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| require $argv[1] ?? dirname(__DIR__, 4) . '/vendor/autoload.php'; | ||
|
|
||
| use FastForward\Config\ArrayConfig; | ||
| use FastForward\Container\ContainerInterface; | ||
| use FastForward\Http\ServiceProvider\HttpServiceProvider; | ||
| use Psr\Http\Client\ClientInterface; | ||
| use Psr\Http\Message\ResponseFactoryInterface; | ||
| use Psr\Http\Message\RequestFactoryInterface; | ||
| use function FastForward\Container\container; | ||
|
|
||
| $config = new ArrayConfig([ContainerInterface::class => [HttpServiceProvider::class]]); | ||
| $container = container($config); | ||
| $response = $container->get(ResponseFactoryInterface::class)->createResponse(202); | ||
| $request = $container->get(RequestFactoryInterface::class)->createRequest('GET', 'https://example.invalid/'); | ||
| $client = $container->get(ClientInterface::class); | ||
| if ($response->getStatusCode() !== 202 || $request->getMethod() !== 'GET' || !$client instanceof ClientInterface) { | ||
| throw new RuntimeException('HTTP composition failed.'); | ||
| } | ||
| try { | ||
| $container->get('application.missing'); | ||
| throw new RuntimeException('Missing service unexpectedly resolved.'); | ||
| } catch (\Psr\Container\NotFoundExceptionInterface) { | ||
| } | ||
|
|
||
| echo "fast-forward-http: ok\n"; |
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,167 @@ | ||||||||
| # Optional installation of fast-forward-http | ||||||||
|
|
||||||||
| `fast-forward/http:^1.2` includes this complete package under | ||||||||
| `resources/skills/fast-forward-http`. Run `composer show fast-forward/http` | ||||||||
| and inspect that path before copying. Earlier releases are outside this skill | ||||||||
| contract. Composer suggestions do not install anything automatically. Library | ||||||||
| installation, discovery-root copies and session activation are separate steps. | ||||||||
|
|
||||||||
| ## Team project with llm/skills | ||||||||
|
|
||||||||
| Use Composer 2 and optionally add `llm/skills:^1.15` as development tooling. | ||||||||
| Start with a project target for reviewable team configuration. Preserve existing | ||||||||
| settings/aliases/approvals when merging these keys into `skills.json` **before** | ||||||||
| installing or enabling the plugin: | ||||||||
|
|
||||||||
| ```json | ||||||||
| { | ||||||||
| "target": ".agents/skills", | ||||||||
| "aliases": [], | ||||||||
| "discovery": false, | ||||||||
| "auto-sync": true, | ||||||||
| "vendor-sources": false, | ||||||||
| "dependencies": { | ||||||||
| "composer": { | ||||||||
| "trusted": ["fast-forward/http"], | ||||||||
| "trusted-replace": true | ||||||||
| } | ||||||||
| } | ||||||||
| } | ||||||||
| ``` | ||||||||
|
|
||||||||
| This replaces implicit dependency trust with a narrow donor allowlist, disables | ||||||||
| remote vendor sources and requests no host aliases. A deliberate | ||||||||
| `fast-forward/*` allowlist grants broader organizational trust. Use the actual | ||||||||
| host's project discovery root; Claude Code can choose `.claude/skills`. | ||||||||
| Do not erase intentional aliases or other donors in an existing manifest. | ||||||||
|
|
||||||||
| If the application owner has authorized this plugin's execution, merge its | ||||||||
| root approval, install it and inspect the report: | ||||||||
|
|
||||||||
| ```sh | ||||||||
| composer config allow-plugins.llm/skills true | ||||||||
| composer require --dev 'llm/skills:^1.15' | ||||||||
| composer skills:show | ||||||||
| ``` | ||||||||
|
|
||||||||
| The donor only suggests the tool; it neither requires it at runtime nor grants | ||||||||
| this approval on behalf of consumers. Commit the chosen manifest, skills.json, | ||||||||
| application lockfile and intended project copies according to project policy. | ||||||||
| Approved Composer install/update operations then perform automatic sync. | ||||||||
|
|
||||||||
| For manual timing, choose `auto-sync:false` before installation and use: | ||||||||
|
|
||||||||
| ```sh | ||||||||
| composer skills:show | ||||||||
| composer skills:update fast-forward/http --dry-run | ||||||||
| composer skills:update fast-forward/http | ||||||||
| ``` | ||||||||
|
|
||||||||
| Explicitly naming a donor selects/trusts it for that run. Test automatic trust | ||||||||
| without a package argument when that policy is what matters. With Composer | ||||||||
| 2.10.3 and llm/skills 1.15.0, `--no-scripts` alone still permits automatic copy; | ||||||||
| `auto-sync:false` disables automatic sync and `--no-plugins` stops plugin loading. | ||||||||
| Verify these behaviors again after changing tool versions. | ||||||||
|
|
||||||||
| ## Update and removal boundaries | ||||||||
|
|
||||||||
| A 1.15 sync overwrites incoming same-path files. It retains extra local files | ||||||||
| and files removed from the donor's next version. Removing a donor or uninstalling | ||||||||
| the plugin does not delete its existing instruction copies. Regard the copy as | ||||||||
| donor-owned; keep deliberate local instructions in a separate skill name. | ||||||||
| Record the installed donor/tool versions and review diffs before each refresh. | ||||||||
|
|
||||||||
| Inspect cleanup without applying it: | ||||||||
|
|
||||||||
| ```sh | ||||||||
| composer skills:update --clean --dry-run | ||||||||
| ``` | ||||||||
|
|
||||||||
| An unscoped clean can remove all target skills, including handwritten ones. | ||||||||
| Scoped clean reinstalls the current selection; it cannot locate an absent donor | ||||||||
| by historical ownership. Inventory affected directories, back up outside | ||||||||
| discovery, and obtain authority before any destructive cleanup. Do not add a | ||||||||
| root-wide clean hook. | ||||||||
|
|
||||||||
| ## Guarded manual copying | ||||||||
|
|
||||||||
| Choose the existing project root, then copy all files together: | ||||||||
|
|
||||||||
| ```sh | ||||||||
| skill_source="vendor/fast-forward/http/resources/skills/fast-forward-http" | ||||||||
| skill_target=".agents/skills/fast-forward-http" | ||||||||
| test -f "$skill_source/SKILL.md" && | ||||||||
| test ! -e "$skill_target" && | ||||||||
| test ! -L "$skill_target" && | ||||||||
| mkdir -p "$(dirname "$skill_target")" && | ||||||||
| cp -R "$skill_source" "$skill_target" | ||||||||
| ``` | ||||||||
|
|
||||||||
| Both existing directories and dangling links are refused. Global use is an | ||||||||
| explicit alternative: set skill_target to | ||||||||
| `$HOME/.agents/skills/fast-forward-http` for Codex or the configured | ||||||||
| `$HOME/.claude/skills/fast-forward-http` for Claude Code. | ||||||||
| Do not create a symlink into replaceable vendor content. A globally installed | ||||||||
| Composer plugin does not constitute a global instruction copy. | ||||||||
|
|
||||||||
| For a selected manual update/removal, first move only that package into a unique | ||||||||
| backup outside discovery: | ||||||||
|
|
||||||||
| ```sh | ||||||||
| skill_backup="$HOME/.agent-skill-backups/fast-forward-http-$(date +%Y%m%d%H%M%S)-$$" | ||||||||
| test -d "$skill_target" && | ||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win Fail clearly when This block uses Add an explicit precondition or repeat the target assignment in this block. Proposed guard--- "a/resources/skills/fast-forward-http/references/installation.md"
+++ "b/resources/skills/fast-forward-http/references/installation.md"
@@ -108,8 +108,9 @@
backup outside discovery:
```sh
skill_backup="$HOME/.agent-skill-backups/fast-forward-http-$(date +%Y%m%d%H%M%S)-$$"
+: "${skill_target:?Set skill_target to the selected project or global target}"
test -d "$skill_target" &&
test ! -L "$skill_target" &&
test ! -e "$skill_backup" &&
test ! -L "$skill_backup" &&📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||
| test ! -L "$skill_target" && | ||||||||
| test ! -e "$skill_backup" && | ||||||||
| test ! -L "$skill_backup" && | ||||||||
| mkdir -p "$(dirname "$skill_backup")" && | ||||||||
| mv "$skill_target" "$skill_backup" | ||||||||
| ``` | ||||||||
|
|
||||||||
| For an update review the new source, then repeat the guarded copy. To roll back, | ||||||||
| archive any replacement and restore the saved whole directory to the same | ||||||||
| target. A manager-owned copy may return on its next sync until the consumer | ||||||||
| changes that donor's trust/dependency configuration. Keep backups out of every | ||||||||
| discovery directory. | ||||||||
|
|
||||||||
| ## Optional Skills CLI | ||||||||
|
|
||||||||
| Requires npm, Node.js 22.20.0+ and Git for repository sources. The reviewed pin | ||||||||
| is skills@1.7.2; evaluate version changes separately. Choose only the actual host: | ||||||||
|
|
||||||||
| ```sh | ||||||||
| npx --yes skills@1.7.2 add ./vendor/fast-forward/http/resources/skills/fast-forward-http --skill fast-forward-http --agent codex --copy --yes | ||||||||
| npx --yes skills@1.7.2 list --agent codex | ||||||||
| ``` | ||||||||
|
|
||||||||
| Use `--agent claude-code` for that host. Add `--global` to both commands only | ||||||||
| when global scope was selected. Preserve/commit intended project copies and the | ||||||||
| CLI's project lockfile. For a remote source first set SKILL_REF to a reviewed | ||||||||
| immutable commit: | ||||||||
|
|
||||||||
| ```sh | ||||||||
| npx --yes skills@1.7.2 add "https://github.com/php-fast-forward/http/tree/$SKILL_REF/resources/skills/fast-forward-http" --skill fast-forward-http --agent codex --copy --yes | ||||||||
| ``` | ||||||||
|
|
||||||||
| Review the new revision and back up local edits before repeating for an update. | ||||||||
| Remove the chosen package/scope with: | ||||||||
|
|
||||||||
| ```sh | ||||||||
| npx --yes skills@1.7.2 remove fast-forward-http --agent codex --yes | ||||||||
| # Only for a selected global copy: | ||||||||
| npx --yes skills@1.7.2 remove fast-forward-http --agent codex --global --yes | ||||||||
| ``` | ||||||||
|
|
||||||||
| After every route inspect the complete files, refresh the agent session, | ||||||||
| confirm the public name is discovered and perform a bounded consumer task. | ||||||||
| A copy, listing and successful task are separate observations. | ||||||||
|
|
||||||||
| Tool contracts: [llm/skills 1.15.0](https://github.com/roxblnfk/skills/tree/1.15.0), | ||||||||
| [Composer plugin approval](https://getcomposer.org/doc/06-config.md#allow-plugins) | ||||||||
| and [Skills CLI](https://github.com/vercel-labs/skills). | ||||||||
|
|
||||||||
| The Skills CLI 1.7.2 removal report is not proof that the canonical project | ||||||||
| `.agents/skills` directory disappeared. A Codex project exercise reported one | ||||||||
| removal while that copied package remained. Inspect the actual target and CLI | ||||||||
| lockfiles afterwards. If an obsolete copy remains, verify that no other host | ||||||||
| uses it, then archive only that selected directory outside discovery using the | ||||||||
| manual recovery procedure above. Do not run a blanket clean to compensate. | ||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
Repository: php-fast-forward/http
Length of output: 18172
🌐 Web query:
llm/skills 1.15.0 Composer --no-scripts automatic sync documentation💡 Result:
🏁 Script executed:
Repository: php-fast-forward/http
Length of output: 10152
Correct the
--no-scriptsguidance.llm/skills1.15.0 documents thatcomposer install --no-scriptssuppresses automatic synchronization for that invocation.Suggested fix
📝 Committable suggestion
🤖 Prompt for AI Agents