English | 繁體中文
Reference sibling actions in your own repository with uses: ./../org/repo/... —
even when your composite action is consumed remotely.
Pure bash, no extra checkout, no tokens, no permissions.
Your repository ships a composite action that calls another local action in the same repo:
# org/repo/.github/actions/main/action.yml
runs:
using: 'composite'
steps:
- uses: ./.github/actions/helper # ❌This works inside your own workflows, but the moment someone consumes your action
remotely (uses: org/repo/.github/actions/main@v1), it fails with a confusing error:
Error: Can't find 'action.yml' under '...'. Did you forget to run actions/checkout?
That's because uses: ./... resolves against the consumer's $GITHUB_WORKSPACE,
not your action's own checkout under _actions/.
Add one step at the top of your composite action, then reference your local actions
through ./../org/repo/...:
# org/repo/.github/actions/main/action.yml
runs:
using: 'composite'
steps:
- uses: wei18/local-composite-action@v1
with:
action_repository: ${{ github.action_repository }}
action_path: ${{ github.action_path }}
- name: Run a local action from the same repository
uses: ./../org/repo/.github/actions/helper # ✅
- name: Run another one
uses: ./../org/repo/.github/actions/another-helper # ✅Important
Write the ./../org/repo/... part in all lowercase — a lowercase symlink is
always created, regardless of how the caller's uses: line is cased.
The runner checks your action out under _actions/, while uses: ./<path> resolves
relative to $GITHUB_WORKSPACE. This action bridges the two with a single symlink:
/home/runner/work
├── _actions/org/repo/v1/ ◄─┐ your action's checkout
├── org/repo ─────────────────┘ symlink created by this action
└── consumer/consumer/ $GITHUB_WORKSPACE
uses: ./../org/repo/<path> then resolves through the symlink into your checkout —
the exact same commit the consumer pinned, with paths matching your repo layout.
- ✅ No
permissions:required - ✅ No tokens or secrets
- ✅ No network access — pure bash, zero dependencies
| local-composite-action | second actions/checkout |
|
|---|---|---|
| Extra clone | none — reuses the existing checkout | full fetch per job |
| Private repos | works out of the box | needs a token/PAT |
| Version drift | always the consumer's pinned ref | ref must be duplicated and kept in sync |
| Workspace | untouched | risks clobbering consumer files |
GitHub has proposed a native $/ syntax
(e.g. uses: $/path/to/action) that resolves sibling actions in the same
repository at the same SHA. As of mid-2026 it is still a proposal with no
release date.
| local-composite-action | native $/ (proposed) |
|
|---|---|---|
| Available today | ✅ | not yet shipped |
| Same-repo sibling actions | ✅ | ✅ once shipped |
| Cross-repository references | ✅ any repo already under _actions* |
out of scope |
* pass that repository's org/repo as action_repository explicitly.
Once $/ ships, prefer it for same-repo references — this action remains useful
for cross-repository layouts, which $/ explicitly does not cover.
| Name | Description | Required |
|---|---|---|
action_repository |
Your action's org/repo. Pass ${{ github.action_repository }} |
✅ |
action_path |
Your composite action's path. Pass ${{ github.action_path }} |
Recommended* |
* Without action_path, the repository is located by searching the runner's
_actions directory, which can be ambiguous if the same repository is used at
multiple refs within one job. Passing it makes resolution exact.
Could not find action repository (org/repo) from path (...)
The provided path doesn't sit inside your repository's checkout and the _actions
fallback found nothing. Pass both inputs as shown in the fix.
action_repository is empty
GITHUB_ACTION_REPOSITORY is empty when an action is referenced by a local path
(uses: ./...). In that case symlinks aren't needed — or pass your org/repo explicitly.
Can't find 'action.yml' on the ./../org/repo/... step
Check that the ./../org/repo part is all lowercase and that this action ran
before the failing step in the same composite action.
Every push and pull request runs a unit test suite against simulated runner layouts, plus a self-referential integration test — this repository uses its own action to test itself.
MIT © wei18
