diff --git a/.github/release-rules/checks.json b/.github/release-rules/checks.json new file mode 100644 index 0000000..31b7ef6 --- /dev/null +++ b/.github/release-rules/checks.json @@ -0,0 +1,64 @@ +{ + "target": "branch", + "enforcement": "active", + "conditions": { + "ref_name": { + "include": [ + "refs/heads/main" + ], + "exclude": [] + } + }, + "name": "Gem release checks", + "bypass_actors": [ + { + "actor_id": 5, + "actor_type": "RepositoryRole", + "bypass_mode": "pull_request" + } + ], + "rules": [ + { + "type": "required_status_checks", + "parameters": { + "strict_required_status_checks_policy": true, + "do_not_enforce_on_create": false, + "required_status_checks": [ + { + "context": "3.3 on ubuntu" + }, + { + "context": "3.3 on macos" + }, + { + "context": "3.4 on ubuntu" + }, + { + "context": "3.4 on macos" + }, + { + "context": "4.0 on ubuntu" + }, + { + "context": "4.0 on macos" + }, + { + "context": "check" + }, + { + "context": "ruby on ubuntu" + }, + { + "context": "ruby on macos" + }, + { + "context": "validate" + }, + { + "context": "Release validation" + } + ] + } + } + ] +} diff --git a/.github/release-rules/history.json b/.github/release-rules/history.json new file mode 100644 index 0000000..e6f4af1 --- /dev/null +++ b/.github/release-rules/history.json @@ -0,0 +1,22 @@ +{ + "target": "branch", + "enforcement": "active", + "conditions": { + "ref_name": { + "include": [ + "refs/heads/main" + ], + "exclude": [] + } + }, + "name": "Gem release history", + "bypass_actors": [], + "rules": [ + { + "type": "deletion" + }, + { + "type": "non_fast_forward" + } + ] +} diff --git a/.github/release-rules/reviews.json b/.github/release-rules/reviews.json new file mode 100644 index 0000000..b36fd66 --- /dev/null +++ b/.github/release-rules/reviews.json @@ -0,0 +1,37 @@ +{ + "target": "branch", + "enforcement": "active", + "conditions": { + "ref_name": { + "include": [ + "refs/heads/main" + ], + "exclude": [] + } + }, + "name": "Gem release reviews", + "bypass_actors": [ + { + "actor_id": 5, + "actor_type": "RepositoryRole", + "bypass_mode": "pull_request" + } + ], + "rules": [ + { + "type": "pull_request", + "parameters": { + "required_approving_review_count": 2, + "dismiss_stale_reviews_on_push": true, + "require_last_push_approval": true, + "required_review_thread_resolution": true, + "require_code_owner_review": false, + "allowed_merge_methods": [ + "merge", + "squash", + "rebase" + ] + } + } + ] +} diff --git a/.github/release-rules/tags.json b/.github/release-rules/tags.json new file mode 100644 index 0000000..8f7a46f --- /dev/null +++ b/.github/release-rules/tags.json @@ -0,0 +1,22 @@ +{ + "name": "Gem release tags", + "target": "tag", + "enforcement": "active", + "bypass_actors": [], + "conditions": { + "ref_name": { + "include": [ + "refs/tags/v*" + ], + "exclude": [] + } + }, + "rules": [ + { + "type": "deletion" + }, + { + "type": "non_fast_forward" + } + ] +} diff --git a/.github/workflows/release-prepare.yaml b/.github/workflows/release-prepare.yaml new file mode 100644 index 0000000..1dc024f --- /dev/null +++ b/.github/workflows/release-prepare.yaml @@ -0,0 +1,52 @@ +name: Prepare release + +on: + workflow_dispatch: + inputs: + bump: + description: Version increment + required: true + type: choice + options: [patch, minor, major] + refresh: + description: Preserve and regenerate an existing release branch + type: boolean + default: false + +permissions: + contents: write + pull-requests: write + +concurrency: + group: release-prepare + cancel-in-progress: false + +env: + BUNDLE_WITH: maintenance + +jobs: + prepare: + if: github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + with: + ref: main + fetch-depth: 0 + persist-credentials: false + - uses: ruby/setup-ruby@v1 + with: + ruby-version: "3.4" + bundler-cache: true + - name: Create release PR + env: + GITHUB_TOKEN: ${{ github.token }} + BUMP: ${{ inputs.bump }} + REFRESH: ${{ inputs.refresh }} + run: | + # GitHub.com's shared Actions bot ID; this identity is not for GitHub Enterprise Server. + # https://github.com/actions/checkout#push-a-commit-using-the-built-in-token + git config user.name 'github-actions[bot]' + git config user.email '41898282+github-actions[bot]@users.noreply.github.com' + case "$BUMP" in patch|minor|major) ;; *) exit 1 ;; esac + bundle exec bake "gem:github:release:$BUMP" "refresh=$REFRESH" diff --git a/.github/workflows/release-publish.yaml b/.github/workflows/release-publish.yaml new file mode 100644 index 0000000..722aac8 --- /dev/null +++ b/.github/workflows/release-publish.yaml @@ -0,0 +1,103 @@ +name: Publish release + +# Inspect the exact pushed commit and publish only a validated, merged release PR. +on: + push: + branches: ["main"] + +permissions: + contents: read + pull-requests: read + +env: + BUNDLE_WITH: maintenance + +jobs: + inspect: + runs-on: ubuntu-latest + outputs: + release: ${{ steps.inspect.outputs.release }} + commit: ${{ steps.inspect.outputs.commit }} + pull_request: ${{ steps.inspect.outputs.pull_request }} + steps: + - uses: actions/checkout@v7 + with: + ref: ${{ github.sha }} + fetch-depth: 0 + persist-credentials: false + - uses: ruby/setup-ruby@v1 + with: + ruby-version: "3.4" + bundler-cache: true + - id: inspect + env: + GITHUB_TOKEN: ${{ github.token }} + RELEASE_COMMIT: ${{ github.sha }} + run: bundle exec bake gem:github:release:resolve + + publish: + needs: inspect + if: needs.inspect.outputs.release == 'true' + runs-on: ubuntu-latest + environment: rubygems + concurrency: + group: release-publish + cancel-in-progress: false + queue: max + env: + RELEASE_PR: ${{ needs.inspect.outputs.pull_request }} + permissions: + contents: write + pull-requests: read + actions: read + id-token: write + attestations: write + steps: + - uses: actions/checkout@v7 + with: + # Inspection verified this merged commit belongs to the default branch. + ref: ${{ needs.inspect.outputs.commit }} + fetch-depth: 0 + persist-credentials: false + - uses: ruby/setup-ruby@v1 + with: + ruby-version: "3.4" + rubygems: '4.0.21' + bundler-cache: true + - name: Build or restore artifact + id: build + env: + GITHUB_TOKEN: ${{ github.token }} + GEM_SIGNING_KEY: ${{ secrets.GEM_SIGNING_KEY }} + run: bundle exec bake gem:github:release:build + - name: Sign RubyGems attestation + if: steps.build.outputs.restored != 'true' + env: + PACKAGE: ${{ steps.build.outputs.package }} + run: gem exec sigstore-cli:0.2.3 sign "$PACKAGE" --bundle "$PACKAGE.sigstore.json" + - name: Attest gem and release receipt + if: steps.build.outputs.restored != 'true' + id: attest + uses: actions/attest@v4 + with: + subject-path: | + ${{ steps.build.outputs.package }} + pkg/release.json + - name: Retain provenance bundle + if: steps.build.outputs.restored != 'true' + env: + ATTESTATION_BUNDLE: ${{ steps.attest.outputs.bundle-path }} + run: cp "$ATTESTATION_BUNDLE" pkg/provenance.sigstore.json + - name: Preserve release before upload + if: steps.build.outputs.restored != 'true' + uses: actions/upload-artifact@v7 + with: + name: ${{ steps.build.outputs.artifact }} + path: pkg/ + if-no-files-found: error + retention-days: 90 + - uses: rubygems/configure-rubygems-credentials@main + - name: Verify, publish, and finalize + env: + GITHUB_TOKEN: ${{ github.token }} + run: bundle exec bake gem:github:release:publish diff --git a/.github/workflows/release-validate.yaml b/.github/workflows/release-validate.yaml new file mode 100644 index 0000000..5d6c9f3 --- /dev/null +++ b/.github/workflows/release-validate.yaml @@ -0,0 +1,32 @@ +name: Validate release + +on: + pull_request: + branches: ["main"] + +permissions: + contents: read + +env: + BUNDLE_WITH: maintenance + +jobs: + validate: + name: Release validation + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + with: + ref: ${{ github.event.pull_request.head.sha }} + fetch-depth: 0 + persist-credentials: false + - uses: ruby/setup-ruby@v1 + with: + ruby-version: "3.4" + bundler-cache: true + - name: Regenerate release content + env: + RELEASE_BASE: ${{ github.event.pull_request.base.sha }} + run: bundle exec bake gem:github:release:validate "base=$RELEASE_BASE" + - name: Build unsigned package + run: bundle exec bake gem:build signing_key=false diff --git a/agent-context.gemspec b/agent-context.gemspec index 3950bed..329a15e 100644 --- a/agent-context.gemspec +++ b/agent-context.gemspec @@ -11,7 +11,7 @@ Gem::Specification.new do |spec| spec.license = "MIT" spec.cert_chain = ["release.cert"] - spec.signing_key = File.expand_path("~/.gem/release.pem") + spec.signing_key = File.expand_path("~/.gem/socketry-release.pem") spec.homepage = "https://github.com/ioquatix/agent-context" diff --git a/bake.rb b/bake.rb index 9441211..c9c2a0a 100644 --- a/bake.rb +++ b/bake.rb @@ -7,13 +7,7 @@ # # @parameter version [String] The new version number. def after_gem_release_version_increment(version) + context["modernize:license"].call context["releases:update"].call(version) context["utopia:project:update"].call end - -# Create a GitHub release for the given tag. -# -# @parameter tag [String] The tag to create a release for. -def after_gem_release(tag:, **options) - context["releases:github:release"].call(tag) -end diff --git a/config/release.yaml b/config/release.yaml new file mode 100644 index 0000000..2f79ca2 --- /dev/null +++ b/config/release.yaml @@ -0,0 +1,20 @@ +--- +schema: 1 +repository: socketry/agent-context +branch: main +checks: +- 3.3 on ubuntu +- 3.3 on macos +- 3.4 on ubuntu +- 3.4 on macos +- 4.0 on ubuntu +- 4.0 on macos +- check +- ruby on ubuntu +- ruby on macos +- validate +- Release validation +approvals: 2 +signing: true +ruby: '3.4' +environment: rubygems diff --git a/context/index.yaml b/context/index.yaml new file mode 100644 index 0000000..c856e9d --- /dev/null +++ b/context/index.yaml @@ -0,0 +1,15 @@ +# Automatically generated context index for Utopia::Project guides. +# Do not edit then files in this directory directly, instead edit the guides and then run `bake utopia:project:agent:context:update`. +--- +description: Install and manage context files and skills from Ruby gems. +metadata: + bug_tracker_uri: https://github.com/ioquatix/agent-context/issues + changelog_uri: https://github.com/ioquatix/agent-context/blob/main/releases.md + documentation_uri: https://ioquatix.github.io/agent-context/ + funding_uri: https://github.com/sponsors/ioquatix/ + source_code_uri: https://github.com/ioquatix/agent-context.git +files: +- path: getting-started.md + title: Getting Started + description: This guide explains how to install package guidance and skills using + `agent-context`. diff --git a/gems.rb b/gems.rb index 3e80639..0ba2cf1 100644 --- a/gems.rb +++ b/gems.rb @@ -9,7 +9,7 @@ gemspec group :maintenance, optional: true do - gem "bake-gem" + gem "bake-gem-github" gem "bake-modernize" gem "bake-releases" diff --git a/guides/getting-started/readme.md b/guides/getting-started/readme.md index 1661dca..36eb0ca 100644 --- a/guides/getting-started/readme.md +++ b/guides/getting-started/readme.md @@ -38,10 +38,10 @@ bake agent:context:list --gem async # View a specific context file bake agent:context:show --gem async --file thread-safety -# List, show, or install dependency skills -bake agent:context:skill:list -bake agent:context:skill:show --gem provider --skill provider-workflow -bake agent:context:skill:install --gem provider --skill provider-workflow +# List, show, or install a skill through the context tasks +bake agent:context:list --gem provider +bake agent:context:show --gem provider --file workflow +bake agent:context:install --gem provider ``` ## Understanding context/ vs .agents/context/ diff --git a/readme.md b/readme.md index ddd9beb..7863e2c 100644 --- a/readme.md +++ b/readme.md @@ -38,7 +38,7 @@ When you install context from other gems, they will be placed in `.agents/contex Please see the [project documentation](https://ioquatix.github.io/agent-context/) for more details. - - [Getting Started](https://ioquatix.github.io/agent-context/guides/getting-started/index) - This guide explains how to use `agent-context`, a tool for discovering and installing contextual information from Ruby gems to help AI agents. + - [Getting Started](https://ioquatix.github.io/agent-context/guides/getting-started/index) - This guide explains how to install package guidance and skills using `agent-context`. ### Installation @@ -112,7 +112,7 @@ Use descriptive filenames and focused Markdown guides. Agents find the installed A root-level context document can declare a skill: -```markdown +``` markdown --- metadata: type: skill @@ -139,6 +139,15 @@ See [the portable specification](specification.md) and [Getting Started](guides/ Please see the [project releases](https://ioquatix.github.io/agent-context/releases/index) for all releases. +### Unreleased + + - Resolve context source filenames before installed skill names and show authored content consistently. + - Install unfamiliar context types as ordinary guidance so providers can introduce new types. + - Store resolved skill provenance in `SKILL.md` front matter under `metadata`, with `metadata.type: skill` declaring skills. + - Preserve authored names, descriptions, additional metadata, and the original Markdown body using native front matter AST nodes. + - Share loaded documents between context and skill installation, and use direct writes with rerunnable progress. + - Discover dependency guidance through installed Markdown files and the list/show commands. Remove generated indexes and the `agent:context:index` task. + ### v0.3.0 - Rename `agent.md` -\> `agents.md`. @@ -180,12 +189,14 @@ $ bundle exec sus ### Making Releases -To make a new release: +To prepare a release branch and open a pull request from an up-to-date `main`: ``` bash -$ bundle exec bake gem:release:patch # or minor or major +$ bundle exec bake gem:github:release:patch # or minor or major ``` +See [bake-gem-github](https://github.com/socketry/bake-gem-github) for setup, remote releases, and recovery. + ### Developer Certificate of Origin In order to protect users of this project, we require all contributors to comply with the [Developer Certificate of Origin](https://developercertificate.org/). This ensures that all contributions are properly licensed and attributed. diff --git a/release.cert b/release.cert index d98e595..d88bb2f 100644 --- a/release.cert +++ b/release.cert @@ -1,28 +1,24 @@ -----BEGIN CERTIFICATE----- -MIIE2DCCA0CgAwIBAgIBATANBgkqhkiG9w0BAQsFADBhMRgwFgYDVQQDDA9zYW11 -ZWwud2lsbGlhbXMxHTAbBgoJkiaJk/IsZAEZFg1vcmlvbnRyYW5zZmVyMRIwEAYK -CZImiZPyLGQBGRYCY28xEjAQBgoJkiaJk/IsZAEZFgJuejAeFw0yMjA4MDYwNDUz -MjRaFw0zMjA4MDMwNDUzMjRaMGExGDAWBgNVBAMMD3NhbXVlbC53aWxsaWFtczEd -MBsGCgmSJomT8ixkARkWDW9yaW9udHJhbnNmZXIxEjAQBgoJkiaJk/IsZAEZFgJj -bzESMBAGCgmSJomT8ixkARkWAm56MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIB -igKCAYEAomvSopQXQ24+9DBB6I6jxRI2auu3VVb4nOjmmHq7XWM4u3HL+pni63X2 -9qZdoq9xt7H+RPbwL28LDpDNflYQXoOhoVhQ37Pjn9YDjl8/4/9xa9+NUpl9XDIW -sGkaOY0eqsQm1pEWkHJr3zn/fxoKPZPfaJOglovdxf7dgsHz67Xgd/ka+Wo1YqoE -e5AUKRwUuvaUaumAKgPH+4E4oiLXI4T1Ff5Q7xxv6yXvHuYtlMHhYfgNn8iiW8WN -XibYXPNP7NtieSQqwR/xM6IRSoyXKuS+ZNGDPUUGk8RoiV/xvVN4LrVm9upSc0ss -RZ6qwOQmXCo/lLcDUxJAgG95cPw//sI00tZan75VgsGzSWAOdjQpFM0l4dxvKwHn -tUeT3ZsAgt0JnGqNm2Bkz81kG4A2hSyFZTFA8vZGhp+hz+8Q573tAR89y9YJBdYM -zp0FM4zwMNEUwgfRzv1tEVVUEXmoFCyhzonUUw4nE4CFu/sE3ffhjKcXcY//qiSW -xm4erY3XAgMBAAGjgZowgZcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0O -BBYEFO9t7XWuFf2SKLmuijgqR4sGDlRsMC4GA1UdEQQnMCWBI3NhbXVlbC53aWxs -aWFtc0BvcmlvbnRyYW5zZmVyLmNvLm56MC4GA1UdEgQnMCWBI3NhbXVlbC53aWxs -aWFtc0BvcmlvbnRyYW5zZmVyLmNvLm56MA0GCSqGSIb3DQEBCwUAA4IBgQB5sxkE -cBsSYwK6fYpM+hA5B5yZY2+L0Z+27jF1pWGgbhPH8/FjjBLVn+VFok3CDpRqwXCl -xCO40JEkKdznNy2avOMra6PFiQyOE74kCtv7P+Fdc+FhgqI5lMon6tt9rNeXmnW/ -c1NaMRdxy999hmRGzUSFjozcCwxpy/LwabxtdXwXgSay4mQ32EDjqR1TixS1+smp -8C/NCWgpIfzpHGJsjvmH2wAfKtTTqB9CVKLCWEnCHyCaRVuKkrKjqhYCdmMBqCws -JkxfQWC+jBVeG9ZtPhQgZpfhvh+6hMhraUYRQ6XGyvBqEUe+yo6DKIT3MtGE2+CP -eX9i9ZWBydWb8/rvmwmX2kkcBbX0hZS1rcR593hGc61JR6lvkGYQ2MYskBveyaxt -Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8 -voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg= +MIIEFDCCAnygAwIBAgIBATANBgkqhkiG9w0BAQsFADAwMREwDwYDVQQKDAhTb2Nr +ZXRyeTEbMBkGA1UEAwwSU29ja2V0cnkgUnVieSBHZW1zMB4XDTI2MDkyMTA3NTgx +NFoXDTI3MDkyMTA3NTgxNFowMDERMA8GA1UECgwIU29ja2V0cnkxGzAZBgNVBAMM +ElNvY2tldHJ5IFJ1YnkgR2VtczCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoC +ggGBAM/QgjVgDzDo/xJEQoFvAzcVFP7msnswkhPJB2UDsbxXCZmers5jV512TM5s +NwLHfzJiC4DcI5ax9ZYKM9Q+dS21YYagNqjtg3YPyDqR6phoibEA0VoMuInUQW68 +i5OkCJzYKGD2pYYVZnuFNqyM2ECUvXh/fBmvPoHbncAHhWPaCBH8mQJ8sRNc6+RV +SoZZu1Yo/aW1zQ+SpZwad7s1ZmigfDNHKhJ22KwZHk+/5Zw1QXVfcajjswV0Mm2P +irgjKN3fyNVkwlly63EBlR4VydT+g9QtJtqh7ee0ThhI+v4wYovf4dbLNcEBTHu1 +x1pGbXGx/2fBAST5eVwaXIx1V8VU22AJcBk1H2o5/1F0HfbD2HQjmFOA112KUwBW +9TtspZD3g6rCQFX53XvL9h6j2y1ukl7s5AdEzOe/x6r1MO8tSDtgcYoF89wgF/88 +Q/Eski0FckQ+znfESZcFcpzs2sPDoYW6SNVX4tZcNty85Y6WBHfHKio14x63PeyC +CG1gMwIDAQABozkwNzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQU +SuMc0x24Xshtaa8SQVkBr2Z5WzIwDQYJKoZIhvcNAQELBQADggGBABI62ey5lDWm +j8jsTQaNBMBb7LbKS3XkBwyL1UNGEwlicp399rJDeuNgVSHqBCZ/nE4yleNjgW9Y +N6DKdxXCvXmFUoHvUINeAvThHxmlEGhSfXl1x55xHEig0rEP4jgdjnYdQI4fqeOM +zIDN0F3ruArke4Y62SQgWVN7vspdAA41hBIRl1vsvs0KWG8DIVQ8cmR+TG6zjOmK +iUiUZGNPnStV1O1xW83c+Ba4Am0krP6/forxDPhRvTehqkVYvMdPfYcICNb5IM58 +5vaYvuj5AtfZuZWN0F/0KtSphhNC17rh6h8QmuYdMJ1clvlrkiEaO1UjPVwjgtxC +x/ARh5X6q0/YTXl4r7EfSJEeqW7qhgu9EUj3mGIPHYdX0Dqih/NgK20F3GvQtTfB +7sse0duKBHXONYVwKAsceUVvqtCfyF608bCilCkbhw3QaInRj+BkRQKJ5Tuj2PZR +76a/hwaV2wWn5RtAFBaUQzQdo/xTqJ7IkwaFjOZe/QyvyoRjCK9Rdg== -----END CERTIFICATE----- diff --git a/releases.md b/releases.md index 74c4741..08032da 100644 --- a/releases.md +++ b/releases.md @@ -3,7 +3,6 @@ ## Unreleased - Resolve context source filenames before installed skill names and show authored content consistently. - - Install unfamiliar context types as ordinary guidance so providers can introduce new types. - Store resolved skill provenance in `SKILL.md` front matter under `metadata`, with `metadata.type: skill` declaring skills. - Preserve authored names, descriptions, additional metadata, and the original Markdown body using native front matter AST nodes.