standard_id-apple 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 75dbd2b3cec3ede939959396e75f19d8aea74524af5d94a19ceb3a88ac35fea5
4
- data.tar.gz: a8cbbae0a326e7289c8bd537ab61451a90c39bd93ecca72d6f6aff4c4cc34736
3
+ metadata.gz: 3886bf49958b7ea2704e0491b0e7225c7f82b0d80ca7ab0dcca192b69e7bc1fa
4
+ data.tar.gz: 804f776780574d8457d6037148148c823a1011ffe3e68a8b84362c821f61c623
5
5
  SHA512:
6
- metadata.gz: b34faef3f56f6b1f8e6753b99dbdf5ed11170ecd6d666f3096d3c206b09ccbde0ed9177868c737abd401b8e5025699268b2e9272e106053b87cf355932ad57c9
7
- data.tar.gz: 98dededac1c594d78d430c0c0ccb103912f997cce6369642921fd5568a078ecf9f375bea01535b6373b76e8cc9ac6cf1a3ffd0ddd92fcd78b24eac9a9892b704
6
+ metadata.gz: f124007a84b444fd05c29af8c990cb878a1f9c63a2947309ca719f7e8bda6c0cdbd78d5d793ad404257dca8115ee8b59e5fdc28e320825db75267266826ed261
7
+ data.tar.gz: f90487e071ce29728dab12aa31cee722828e54056b90541ca606ea3e54e4728cba7d7f8458fbfe966212b3b2ce1f99afdda2ead034d7c959c7c17ee71fd8ceae
data/CHANGELOG.md CHANGED
@@ -7,6 +7,76 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.5.0] - 2026-07-31
11
+
12
+ ### Added
13
+
14
+ - **Install generator: `bin/rails g standard_id:apple:install`.** Writes
15
+ `config/initializers/standard_id_apple.rb` with all five `social.apple_*`
16
+ fields wired to ENV, then prints the environment variables the host has to
17
+ set (including the warning that `APPLE_PRIVATE_KEY_PEM` is multi-line and
18
+ that a secret store which flattens it to literal `\n` produces a key that
19
+ parses but fails to sign — surfacing as a JWT error at callback time, not at
20
+ boot). Idempotent: re-running skips an existing initializer; `--force`
21
+ overwrites, `--skip-initializer` writes nothing.
22
+
23
+ It writes a **separate** file rather than editing `standard_id.rb`, so the
24
+ provider can be removed by deleting one file and `standard_id`'s own install
25
+ generator stays free to overwrite its initializer without clobbering these
26
+ credentials. Initializers load alphabetically, so the base config is applied
27
+ first. The generated file uses the `config.social.` form throughout — a spec
28
+ pins that it never emits the unqualified `config.apple_*` form, which works
29
+ today only because the names happen to be unique across scopes.
30
+
31
+ Five of the nine `standard_*` gems shipped an install generator and this was
32
+ not one of them, which left both consumers assembling the block from the
33
+ README by hand.
34
+
35
+ ### Documentation
36
+
37
+ - **Consumer list corrected in `CLAUDE.md`: this gem has two consumers, not
38
+ one.** It named `luminality-web` only; `sidekick-web` also consumes it. Both
39
+ live in sibling workspaces rather than beside this repo, which is how the
40
+ second one went unnoticed.
41
+
42
+ - **Corrected the Configuration section, which was wrong in two ways.**
43
+
44
+ It showed the *flat* form (`config.apple_client_id = ...`) rather than the
45
+ `social` scope the fields actually live in. The flat form works — StandardId
46
+ routes an unqualified name to the owning scope when it is unique across scopes
47
+ — but only once the field is declared, and it silently breaks the day another
48
+ scope declares a colliding name. Existing code using it is not broken.
49
+
50
+ It also documented a form that raised on `standard_id` <= 0.32.0. These fields
51
+ are declared by this gem, and until `standard_id` 0.33.0 they were declared
52
+ from this gem's Railtie `after_initialize` — after `config/initializers` — so
53
+ the plain initializer raised `StandardId::ConfigurationError: Unknown field
54
+ 'apple_client_id' for scope 'social'`. The README now records the
55
+ `after_initialize` workaround for older `standard_id`, states that 0.33.0
56
+ declares provider fields before `:load_config_initializers` so the plain form
57
+ is correct there, and notes that the fields do not exist at all without this
58
+ gem in the Gemfile — on any `standard_id` version.
59
+
60
+ ### Changed
61
+
62
+ - **`standard_id` dependency tightened from `~> 0.1, >= 0.1.7` to `~> 0.29.0`.**
63
+ The old constraint claimed compatibility with every `0.x` release while this
64
+ plugin reaches into `StandardId::ProviderRegistry` and
65
+ `StandardId::Providers::Apple`, and `standard_id` is pre-1.0 with breaking
66
+ minors. Bundler would happily resolve against an untested minor and fail at
67
+ runtime instead of at resolution. Both current consumers already pin
68
+ `standard_id "~> 0.29.0"`, so nothing existing is affected.
69
+
70
+ ### Fixed
71
+
72
+ - Gemspec now uses an allow-list (`Dir["lib/**/*", …]`) rather than a
73
+ `git ls-files` reject-list. A reject-list fails **open** — new files ship
74
+ unless someone remembers to exclude them, which is how `.claude/` reached
75
+ published `0.3.0` of `standard_id-google` (rarebit-one/standard_id-google#69).
76
+ Drops `.editorconfig`, `.pinact.yaml`, `.rspec`, `.rubocop.yml`,
77
+ `.ruby-version`, `AGENTS.md`, `CLAUDE.md`, and `CODE_OF_CONDUCT.md` from the
78
+ package; `lib/` is byte-identical.
79
+
10
80
  ## [0.4.0] - 2026-05-19
11
81
 
12
82
  ### Changed
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) Jaryl Sim
3
+ Copyright (c) 2026 Rarebit One
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining
6
6
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -20,22 +20,76 @@ bundle install
20
20
 
21
21
  The gem automatically registers itself with StandardId when it is required.
22
22
 
23
+ Then run the install generator to drop the credentials block in place:
24
+
25
+ ```bash
26
+ bin/rails g standard_id:apple:install
27
+ ```
28
+
29
+ This writes `config/initializers/standard_id_apple.rb` — deliberately a
30
+ separate file from `config/initializers/standard_id.rb`, so the provider can be
31
+ removed by deleting one file and `standard_id`'s own install generator stays
32
+ free to overwrite its initializer without clobbering these values. Initializers
33
+ load alphabetically, so the base config is applied first. The generator is
34
+ idempotent; re-running on an existing initializer skips with a clear message
35
+ (pass `--force` to overwrite).
36
+
23
37
  ## Configuration
24
38
 
25
- Configure Apple credentials via the StandardId configuration block:
39
+ The generator writes this for you; the block is documented here for hosts
40
+ configuring by hand. Configure Apple credentials via the StandardId
41
+ configuration block, in the `social` scope:
26
42
 
27
43
  ```ruby
44
+ # config/initializers/standard_id.rb
28
45
  StandardId.configure do |config|
29
- config.apple_client_id = ENV["APPLE_CLIENT_ID"]
30
- config.apple_mobile_client_id = ENV["APPLE_MOBILE_CLIENT_ID"] # optional
31
- config.apple_team_id = ENV["APPLE_TEAM_ID"]
32
- config.apple_key_id = ENV["APPLE_KEY_ID"]
33
- config.apple_private_key = ENV["APPLE_PRIVATE_KEY_PEM"]
46
+ config.social.apple_client_id = ENV["APPLE_CLIENT_ID"]
47
+ config.social.apple_mobile_client_id = ENV["APPLE_MOBILE_CLIENT_ID"] # optional
48
+ config.social.apple_team_id = ENV["APPLE_TEAM_ID"]
49
+ config.social.apple_key_id = ENV["APPLE_KEY_ID"]
50
+ config.social.apple_private_key = ENV["APPLE_PRIVATE_KEY_PEM"]
34
51
  end
35
52
  ```
36
53
 
37
54
  With those values in place, StandardId routes such as `/auth/callback/apple` continue to function using this provider gem.
38
55
 
56
+ ### Two corrections to earlier versions of this section
57
+
58
+ **The `social.` prefix.** This section previously showed the flat form
59
+ (`config.apple_client_id = ...`). That happens to work — `StandardId`'s top-level
60
+ config routes an unqualified name to the owning scope when it is unique across
61
+ scopes, and these five are — but only *after* the field has been declared, and it
62
+ is the wrong thing to document: the fields live in the `social` scope, the
63
+ install template writes them there, and the flat form silently stops working the
64
+ day another scope declares a colliding name. Existing code using the flat form is
65
+ not broken and needs no change.
66
+
67
+ **Boot ordering.** These fields are declared by *this gem*, not by
68
+ `standard_id`, and until `standard_id` 0.33.0 they were declared from this gem's
69
+ Railtie `after_initialize` — which runs *after* `config/initializers`. On
70
+ `standard_id` **0.32.0 and earlier**, the block above therefore raised:
71
+
72
+ ```
73
+ StandardId::ConfigurationError: Unknown field 'apple_client_id' for scope 'social'
74
+ ```
75
+
76
+ The workaround was to wrap the writes:
77
+
78
+ ```ruby
79
+ # Only needed on standard_id <= 0.32.0
80
+ Rails.application.config.after_initialize do
81
+ StandardId.configure { |config| config.social.apple_client_id = ENV["APPLE_CLIENT_ID"] }
82
+ end
83
+ ```
84
+
85
+ `standard_id` **>= 0.33.0** declares every loaded provider's fields before
86
+ `:load_config_initializers`, so a plain initializer is correct. The wrapper is no
87
+ longer needed and existing ones keep working unchanged.
88
+
89
+ Note this is about *ordering*, not just versions: **the fields do not exist
90
+ without this gem in your Gemfile**, on any `standard_id` version. Configuring
91
+ `social.apple_*` with the plugin absent raises the same error, correctly.
92
+
39
93
  ## Testing
40
94
 
41
95
  Run the spec suite:
@@ -56,4 +110,4 @@ To release a new version:
56
110
 
57
111
  ## License
58
112
 
59
- MIT — see [LICENSE.txt](LICENSE.txt).
113
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+
5
+ module StandardId
6
+ module Apple
7
+ module Generators
8
+ # Installs the Apple provider's credentials block in a host Rails app.
9
+ #
10
+ # Writes `config/initializers/standard_id_apple.rb` — a separate file from
11
+ # `config/initializers/standard_id.rb` on purpose. The provider is opt-in
12
+ # per app, so its credentials should be removable by deleting one file,
13
+ # and `standard_id`'s own install generator must stay free to overwrite
14
+ # its initializer without clobbering these five values.
15
+ #
16
+ # Initializers load alphabetically, so `standard_id.rb` runs before
17
+ # `standard_id_apple.rb` — the base configuration is already applied by
18
+ # the time this file sets the `social.apple_*` fields.
19
+ #
20
+ # Idempotent: re-running skips an initializer that is already there.
21
+ # `--skip-initializer` opts out; `--force` overwrites.
22
+ class InstallGenerator < Rails::Generators::Base
23
+ source_root File.expand_path("templates", __dir__)
24
+
25
+ INITIALIZER_PATH = "config/initializers/standard_id_apple.rb"
26
+
27
+ desc <<~DESC
28
+ Installs StandardId Apple. This writes #{INITIALIZER_PATH} with the
29
+ five social.apple_* fields wired to ENV, and prints the env vars the
30
+ host needs to set.
31
+
32
+ The generator is idempotent — an existing initializer is skipped with
33
+ a clear message. Pass --force to overwrite.
34
+ DESC
35
+
36
+ class_option :skip_initializer, type: :boolean, default: false,
37
+ desc: "Do not write #{INITIALIZER_PATH}"
38
+ class_option :force, type: :boolean, default: false,
39
+ desc: "Overwrite #{INITIALIZER_PATH} if it already exists"
40
+
41
+ def copy_initializer
42
+ if options[:skip_initializer]
43
+ say_status("skip", "#{INITIALIZER_PATH} (--skip-initializer)", :yellow)
44
+ return
45
+ end
46
+
47
+ if File.exist?(File.join(destination_root, INITIALIZER_PATH)) && !options[:force]
48
+ say_status("identical", "#{INITIALIZER_PATH} (already exists; pass --force to overwrite)", :blue)
49
+ return
50
+ end
51
+
52
+ template "initializer.rb.erb", INITIALIZER_PATH, force: options[:force]
53
+ end
54
+
55
+ def print_env_hint
56
+ return if options[:skip_initializer]
57
+
58
+ say ""
59
+ say "=" * 79
60
+ say "StandardId Apple installed."
61
+ say ""
62
+ say "Set these in the host's environment (1Password / DO app spec / .env):"
63
+ say ""
64
+ say " APPLE_CLIENT_ID the Services ID (web sign-in)"
65
+ say " APPLE_MOBILE_CLIENT_ID the iOS bundle ID — optional, web-only apps skip it"
66
+ say " APPLE_TEAM_ID the 10-character Apple Developer team ID"
67
+ say " APPLE_KEY_ID the key ID of the Sign In with Apple private key"
68
+ say " APPLE_PRIVATE_KEY_PEM the .p8 private key contents, PEM, newlines intact"
69
+ say ""
70
+ say "APPLE_PRIVATE_KEY_PEM is multi-line. Most secret stores flatten it to"
71
+ say "literal \\n — if sign-in fails on a JWT signing error, that is why."
72
+ say "=" * 79
73
+ say ""
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Apple Sign In credentials for StandardId.
4
+ #
5
+ # These five fields are declared by the standard_id-apple gem, NOT by
6
+ # standard_id — they do not exist unless this gem is in the Gemfile, on any
7
+ # standard_id version. Removing the gem and leaving this file behind raises
8
+ # `StandardId::ConfigurationError: Unknown field 'apple_client_id' for scope
9
+ # 'social'`, which is correct behaviour, not a bug.
10
+ #
11
+ # Set them in the `social` scope, as below. The unqualified form
12
+ # (`config.apple_client_id = ...`) happens to work today because StandardId
13
+ # routes a unique unqualified name to its owning scope, but it stops working
14
+ # the day another scope declares a colliding name. Use `config.social.`.
15
+ #
16
+ # On standard_id <= 0.32.0 these fields were declared from this gem's Railtie
17
+ # `after_initialize`, which runs AFTER config/initializers — so the plain block
18
+ # below raised at boot and had to be wrapped:
19
+ #
20
+ # Rails.application.config.after_initialize do
21
+ # StandardId.configure { |config| config.social.apple_client_id = ... }
22
+ # end
23
+ #
24
+ # standard_id >= 0.33.0 declares every loaded provider's fields before
25
+ # `:load_config_initializers`, so the plain form is correct. Existing wrappers
26
+ # keep working and need no change.
27
+ StandardId.configure do |config|
28
+ config.social.apple_client_id = ENV["APPLE_CLIENT_ID"]
29
+
30
+ # Optional: only set when a native iOS client signs in against the same
31
+ # backend. Its audience differs from the web Services ID, so leaving it nil
32
+ # on a web-only app is correct — don't point it at APPLE_CLIENT_ID.
33
+ config.social.apple_mobile_client_id = ENV["APPLE_MOBILE_CLIENT_ID"]
34
+
35
+ config.social.apple_team_id = ENV["APPLE_TEAM_ID"]
36
+ config.social.apple_key_id = ENV["APPLE_KEY_ID"]
37
+
38
+ # The .p8 contents in PEM form, newlines intact. Secret stores that flatten
39
+ # multi-line values to literal \n produce a key that parses but fails to
40
+ # sign — surfacing as a JWT error at callback time, not at boot.
41
+ config.social.apple_private_key = ENV["APPLE_PRIVATE_KEY_PEM"]
42
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module StandardId
4
4
  module Apple
5
- VERSION = "0.4.0"
5
+ VERSION = "0.5.0"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,11 +1,11 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: standard_id-apple
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jaryl Sim
8
- bindir: exe
8
+ bindir: bin
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
@@ -47,22 +47,22 @@ dependencies:
47
47
  name: standard_id
48
48
  requirement: !ruby/object:Gem::Requirement
49
49
  requirements:
50
- - - "~>"
51
- - !ruby/object:Gem::Version
52
- version: '0.1'
53
50
  - - ">="
54
51
  - !ruby/object:Gem::Version
55
- version: 0.1.7
52
+ version: '0.29'
53
+ - - "<"
54
+ - !ruby/object:Gem::Version
55
+ version: '1.0'
56
56
  type: :runtime
57
57
  prerelease: false
58
58
  version_requirements: !ruby/object:Gem::Requirement
59
59
  requirements:
60
- - - "~>"
61
- - !ruby/object:Gem::Version
62
- version: '0.1'
63
60
  - - ">="
64
61
  - !ruby/object:Gem::Version
65
- version: 0.1.7
62
+ version: '0.29'
63
+ - - "<"
64
+ - !ruby/object:Gem::Version
65
+ version: '1.0'
66
66
  description: Extracted StandardId::Providers::Apple implementation packaged as a standalone
67
67
  gem so StandardId installations can opt into Sign in with Apple independently.
68
68
  email:
@@ -71,17 +71,12 @@ executables: []
71
71
  extensions: []
72
72
  extra_rdoc_files: []
73
73
  files:
74
- - ".editorconfig"
75
- - ".rspec"
76
- - ".rubocop.yml"
77
- - ".ruby-version"
78
- - AGENTS.md
79
74
  - CHANGELOG.md
80
- - CLAUDE.md
81
- - CODE_OF_CONDUCT.md
82
- - LICENSE.txt
75
+ - LICENSE
83
76
  - README.md
84
77
  - Rakefile
78
+ - lib/generators/standard_id/apple/install/install_generator.rb
79
+ - lib/generators/standard_id/apple/install/templates/initializer.rb.erb
85
80
  - lib/standard_id/apple.rb
86
81
  - lib/standard_id/apple/providers/apple.rb
87
82
  - lib/standard_id/apple/railtie.rb
data/.editorconfig DELETED
@@ -1,15 +0,0 @@
1
- root = true
2
-
3
- [*]
4
- indent_style = space
5
- indent_size = 2
6
- end_of_line = lf
7
- charset = utf-8
8
- trim_trailing_whitespace = true
9
- insert_final_newline = true
10
-
11
- [*.md]
12
- trim_trailing_whitespace = false
13
-
14
- [Makefile]
15
- indent_style = tab
data/.rspec DELETED
@@ -1,3 +0,0 @@
1
- --format documentation
2
- --color
3
- --require spec_helper
data/.rubocop.yml DELETED
@@ -1,8 +0,0 @@
1
- # Omakase Ruby styling for Rails
2
- inherit_gem: { rubocop-rails-omakase: rubocop.yml }
3
-
4
- # Overwrite or add rules to create your own house style
5
-
6
- # Use `[a, [b, c]]` not `[ a, [ b, c ] ]`
7
- Layout/SpaceInsideArrayLiteralBrackets:
8
- EnforcedStyle: no_space
data/.ruby-version DELETED
@@ -1 +0,0 @@
1
- 4.0.1
data/AGENTS.md DELETED
@@ -1,72 +0,0 @@
1
- # AGENTS.md - AI Agent Guide for standard_id-apple
2
-
3
- `standard_id-apple` is a provider plugin for the [StandardId](https://github.com/rarebit-one/standard_id) authentication engine. It packages a `StandardId::Providers::Apple` implementation for Sign in with Apple, and auto-registers itself with the host StandardId installation via a `Rails::Railtie` so apps that bundle the gem don't need an explicit initializer.
4
-
5
- ## Quick Reference
6
-
7
- ```bash
8
- # Run tests
9
- bundle exec rspec
10
-
11
- # Run a single spec file
12
- bundle exec rspec spec/standard_id/apple/providers/apple_spec.rb
13
-
14
- # Run linting (note: --config flag is required on Ruby 4.0)
15
- bundle exec rubocop --config .rubocop.yml
16
-
17
- # Auto-fix lint issues
18
- bundle exec rubocop --config .rubocop.yml -A
19
- ```
20
-
21
- ## Project Structure
22
-
23
- ```
24
- standard_id-apple/
25
- ├── lib/standard_id/
26
- │ ├── apple.rb # Top-level require entrypoint
27
- │ └── apple/
28
- │ ├── version.rb # Gem version constant
29
- │ ├── railtie.rb # Auto-registers provider on after_initialize
30
- │ └── providers/apple.rb # StandardId::Providers::Apple implementation
31
- └── spec/
32
- ├── spec_helper.rb # Boots a minimal Rails app so the Railtie fires
33
- └── standard_id/ # Provider specs
34
- ```
35
-
36
- ## Key Patterns
37
-
38
- ### Provider class
39
-
40
- `StandardId::Providers::Apple` inherits from `StandardId::Providers::Base` (defined in the parent `standard_id` gem) and implements the provider contract: `provider_name`, `authorization_url`, `get_user_info`, `config_schema`, plus Apple-specific helpers (`verify_id_token`, `generate_client_secret`, JWKS fetching).
41
-
42
- ### Railtie auto-registration
43
-
44
- `StandardId::Apple::Railtie` runs on `config.after_initialize` and calls `StandardId::ProviderRegistry.register(:apple, StandardId::Providers::Apple)`. Host apps just need the gem in their Gemfile — no initializer required.
45
-
46
- ### Spec bootstrapping
47
-
48
- `spec/spec_helper.rb` defines a tiny `Rails::Application` and calls `Rails.application.initialize!` so the Railtie's `after_initialize` hook fires during the spec run; without this the provider would not appear in the registry.
49
-
50
- ## Key Files
51
-
52
- | File | Purpose |
53
- |------|---------|
54
- | `lib/standard_id/apple.rb` | Top-level require entrypoint |
55
- | `lib/standard_id/apple/railtie.rb` | Provider registration on Rails boot |
56
- | `lib/standard_id/apple/providers/apple.rb` | Apple provider implementation |
57
- | `lib/standard_id/apple/version.rb` | Gem version constant |
58
- | `standard_id-apple.gemspec` | Gem metadata + runtime deps |
59
-
60
- ## Dependencies
61
-
62
- - **standard_id** `~> 0.1`, `>= 0.1.7` (parent engine — provides `Providers::Base`, `ProviderRegistry`, errors)
63
- - **activesupport** `>= 8.0` (`Time.current`, `present?`/`blank?`, indifferent access)
64
- - **jwt** `~> 2.7` (id_token decoding, client_secret signing)
65
-
66
- Dev: rspec, rubocop, webmock, lefthook.
67
-
68
- ## Testing
69
-
70
- - WebMock stubs Apple's JWKS and token endpoints — never make real network calls in specs.
71
- - The dummy Rails app in `spec_helper.rb` is intentionally minimal; add config via `StandardId.config.apple_*` setters in individual specs rather than expanding the dummy app.
72
- - CI runs the full Ruby 4.0.x patch matrix via the shared `rarebit-one/.github` reusable workflow.
data/CLAUDE.md DELETED
@@ -1,32 +0,0 @@
1
- # CLAUDE.md
2
-
3
- ## Worktree-Only Workflow (Enforced)
4
-
5
- **All file modifications are blocked in the main checkout.** A PreToolUse hook (`enforce-worktree.sh`) rejects Edit, Write, and NotebookEdit operations targeting files outside a worktree. There are no opt-outs. Do not use Bash to write files in the main checkout either (e.g., `echo >`, `sed -i`, `tee`, `cp`) — the hook cannot intercept shell commands, so this rule is instruction-enforced.
6
-
7
- Before writing any code, create a worktree:
8
-
9
- ```bash
10
- DEFAULT_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@refs/remotes/origin/@@')
11
- DEFAULT_BRANCH=${DEFAULT_BRANCH:-main}
12
- git fetch origin "$DEFAULT_BRANCH"
13
- git worktree add .worktrees/<name> -b <branch-name> "origin/$DEFAULT_BRANCH"
14
- ```
15
-
16
- Then work inside `.worktrees/<name>/` for the rest of the session.
17
-
18
- **Naming:** Use the Linear issue identifier if available (e.g., `.worktrees/<identifier>`), a task slug (e.g., `.worktrees/fix-auth-timeout`), or today's date (e.g., `.worktrees/2026-04-01`) as fallback.
19
-
20
- **The hook allows modifications only when:**
21
-
22
- 1. The file is inside a git worktree (detected via `git rev-parse --git-dir` returning a path under `.git/worktrees/`)
23
- 2. Running in a CI/automated context where the checkout is already isolated
24
- **Why this matters:** Working directly on the main checkout causes cross-contamination between sessions — uncommitted changes, wrong branches, and dirty state leak into unrelated work. Worktrees eliminate this entirely.
25
-
26
- See the `/worktree` and `/start` skills for full conventions and flags.
27
-
28
- ## Consumers
29
-
30
- `standard_id-apple` is currently consumed by `luminality-web` only in the rarebit-one workspace. Apple Sign In is a Luminality-only feature; `fundbright-web` and `nutripod-web` do not consume this gem.
31
-
32
- After publishing a new version via `/publish-gem`, roll it out with the workspace-level `/rollout-gem standard_id-apple [<version>]` skill (defined at the rarebit-one workspace root, one directory above this repo). The canonical consumer matrix — including version constraints — lives in that skill's `SKILL.md`.
data/CODE_OF_CONDUCT.md DELETED
@@ -1,132 +0,0 @@
1
- # Contributor Covenant Code of Conduct
2
-
3
- ## Our Pledge
4
-
5
- We as members, contributors, and leaders pledge to make participation in our
6
- community a harassment-free experience for everyone, regardless of age, body
7
- size, visible or invisible disability, ethnicity, sex characteristics, gender
8
- identity and expression, level of experience, education, socio-economic status,
9
- nationality, personal appearance, race, caste, color, religion, or sexual
10
- identity and orientation.
11
-
12
- We pledge to act and interact in ways that contribute to an open, welcoming,
13
- diverse, inclusive, and healthy community.
14
-
15
- ## Our Standards
16
-
17
- Examples of behavior that contributes to a positive environment for our
18
- community include:
19
-
20
- * Demonstrating empathy and kindness toward other people
21
- * Being respectful of differing opinions, viewpoints, and experiences
22
- * Giving and gracefully accepting constructive feedback
23
- * Accepting responsibility and apologizing to those affected by our mistakes,
24
- and learning from the experience
25
- * Focusing on what is best not just for us as individuals, but for the overall
26
- community
27
-
28
- Examples of unacceptable behavior include:
29
-
30
- * The use of sexualized language or imagery, and sexual attention or advances of
31
- any kind
32
- * Trolling, insulting or derogatory comments, and personal or political attacks
33
- * Public or private harassment
34
- * Publishing others' private information, such as a physical or email address,
35
- without their explicit permission
36
- * Other conduct which could reasonably be considered inappropriate in a
37
- professional setting
38
-
39
- ## Enforcement Responsibilities
40
-
41
- Community leaders are responsible for clarifying and enforcing our standards of
42
- acceptable behavior and will take appropriate and fair corrective action in
43
- response to any behavior that they deem inappropriate, threatening, offensive,
44
- or harmful.
45
-
46
- Community leaders have the right and responsibility to remove, edit, or reject
47
- comments, commits, code, wiki edits, issues, and other contributions that are
48
- not aligned to this Code of Conduct, and will communicate reasons for moderation
49
- decisions when appropriate.
50
-
51
- ## Scope
52
-
53
- This Code of Conduct applies within all community spaces, and also applies when
54
- an individual is officially representing the community in public spaces.
55
- Examples of representing our community include using an official email address,
56
- posting via an official social media account, or acting as an appointed
57
- representative at an online or offline event.
58
-
59
- ## Enforcement
60
-
61
- Instances of abusive, harassing, or otherwise unacceptable behavior may be
62
- reported to the community leaders responsible for enforcement at
63
- [INSERT CONTACT METHOD].
64
- All complaints will be reviewed and investigated promptly and fairly.
65
-
66
- All community leaders are obligated to respect the privacy and security of the
67
- reporter of any incident.
68
-
69
- ## Enforcement Guidelines
70
-
71
- Community leaders will follow these Community Impact Guidelines in determining
72
- the consequences for any action they deem in violation of this Code of Conduct:
73
-
74
- ### 1. Correction
75
-
76
- **Community Impact**: Use of inappropriate language or other behavior deemed
77
- unprofessional or unwelcome in the community.
78
-
79
- **Consequence**: A private, written warning from community leaders, providing
80
- clarity around the nature of the violation and an explanation of why the
81
- behavior was inappropriate. A public apology may be requested.
82
-
83
- ### 2. Warning
84
-
85
- **Community Impact**: A violation through a single incident or series of
86
- actions.
87
-
88
- **Consequence**: A warning with consequences for continued behavior. No
89
- interaction with the people involved, including unsolicited interaction with
90
- those enforcing the Code of Conduct, for a specified period of time. This
91
- includes avoiding interactions in community spaces as well as external channels
92
- like social media. Violating these terms may lead to a temporary or permanent
93
- ban.
94
-
95
- ### 3. Temporary Ban
96
-
97
- **Community Impact**: A serious violation of community standards, including
98
- sustained inappropriate behavior.
99
-
100
- **Consequence**: A temporary ban from any sort of interaction or public
101
- communication with the community for a specified period of time. No public or
102
- private interaction with the people involved, including unsolicited interaction
103
- with those enforcing the Code of Conduct, is allowed during this period.
104
- Violating these terms may lead to a permanent ban.
105
-
106
- ### 4. Permanent Ban
107
-
108
- **Community Impact**: Demonstrating a pattern of violation of community
109
- standards, including sustained inappropriate behavior, harassment of an
110
- individual, or aggression toward or disparagement of classes of individuals.
111
-
112
- **Consequence**: A permanent ban from any sort of public interaction within the
113
- community.
114
-
115
- ## Attribution
116
-
117
- This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118
- version 2.1, available at
119
- [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
120
-
121
- Community Impact Guidelines were inspired by
122
- [Mozilla's code of conduct enforcement ladder][Mozilla CoC].
123
-
124
- For answers to common questions about this code of conduct, see the FAQ at
125
- [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
126
- [https://www.contributor-covenant.org/translations][translations].
127
-
128
- [homepage]: https://www.contributor-covenant.org
129
- [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
130
- [Mozilla CoC]: https://github.com/mozilla/diversity
131
- [FAQ]: https://www.contributor-covenant.org/faq
132
- [translations]: https://www.contributor-covenant.org/translations