[BUG] APM 0.33.0: apm update fails to integrate Azure Skills because frozen hook metadata is not JSON serializable
Maintainers usually reply within 2 days
@MohammedAlkindi is already working on this.
Since Oct 9, 2026.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 90/100
Research direction
Start from src/apm_cli/integration/hook_native_formats.py: run the issue's repro snippet (json.dumps(_to_claude_hook_entries([{'bash': 'echo test', 'env': {'APM_TEST': 'value'}}]))) to see the mappingproxy failure, then trace where dict(handler.metadata), dict(binding.metadata) and the raw-entry paths only shallow-copy frozen IR produced by _freeze in src/apm_cli/hook_contract.py. Add a recursive materializer (Mapping -> dict, list/tuple -> list, scalars preserved) applied to handler, binding and raw entries in both nested and flat rendering paths. Done when the repro serializes, the existing hook adapter tests still pass, and new tests cover JSON round trips for Claude/Codex/Gemini/nested-flat Antigravity, nested env preservation, and non-mutation of the frozen IR.
Written by the indexing model from the issue text.
Description
With APM CLI 0.33.0, apm update fails while integrating microsoft/azure-skills:
[x] 1 package failed:
+- microsoft/azure-skills -- Failed to integrate primitives: Object of type mappingproxy is not JSON serializable
[x] Installation failed with 1 error(s).
Environment
- APM CLI: 0.33.0
- Reported installation: Windows, WinGet standalone executable and macOS 27.01 (Homebrew)
- Dependency: microsoft/azure-skills
- Targets: claude, codex, copilot
Steps to reproduce
Use APM CLI 0.33.0.
Add microsoft/azure-skills to an APM project with the following configuration.
Run apm update.
name: apm-hook-repro
version: 1.0.0
description: Minimal Azure Skills integration reproduction
author: APM user
targets:
- claude
- codex
- copilot
dependencies:
apm:
- microsoft/azure-skills
The dependency is not pinned here; reproduction depends on it containing hooks with nested metadata, such as an env object.
Expected behavior
APM integrates the hooks successfully, preserving their environment variables
and other metadata in the generated native JSON documents.
Actual behavior
Integration fails with the error above, and the install transaction is not committed.
Root cause
src/apm_cli/hook_contract.py recursively freezes hook metadata in _freeze:
dictionaries become MappingProxyType instances, and lists become tuples.
This is appropriate for the immutable intermediate representation (IR).
However, src/apm_cli/integration/hook_native_formats.py only makes a shallow
copy with dict(handler.metadata) and dict(binding.metadata). Nested mappings
remain frozen. The raw-entry paths also return frozen metadata directly.
Consequently, JSON serialization fails when it encounters a nested mapping proxy.
The failure can be reproduced without downloading Azure Skills or executing hooks:
import json
from apm_cli.integration.hook_native_formats import _to_claude_hook_entries
entries = [{
"bash": "echo test",
"env": {"APM_TEST": "value"},
}]
json.dumps(_to_claude_hook_entries(entries))
Proposed fix
Recursively materialize metadata at the native rendering boundary:
- Convert
Mappingvalues to new dictionaries. - Convert lists and tuples to new lists, recursively converting their elements.
- Preserve scalar values.
- Apply the conversion to handler metadata, binding metadata, and raw entries in
both the nested and flat rendering paths.
Keep the IR immutable. Do not stringify unsupported values with default=str,
discard env, or change dependency declarations as a workaround.
Regression coverage
- JSON round trips for Claude, Codex, Gemini, and nested/flat Antigravity adapters.
- Preservation of nested
env, extension metadata, arrays, and scalar values. - Preservation of commands, timeout conversion, matchers, and provenance.
- Raw-entry round trips, including mappings inside arrays.
- Mutation of rendered output does not mutate the source or frozen IR.
- Gemini's in-place compatibility conversion preserves
env.
- Dominant language
- Python
- Stars
- 4k
- Forks
- 393
- Avg merge
- 4d 23h
- Merged PRs (30d)
- 62
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from microsoft/apm
-
type/automation type/performance
Difficulty 1/5 Under an hour Newbie friendliness 70/100
Maintainers usually reply within 2 days
-
type/automation type/performance
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 2 days
-
type/bug
Difficulty 2/5 1-3 hours Newbie friendliness 61/100
Maintainers usually reply within 2 days
-
type/automation type/performance
Difficulty 2/5 1-3 hours Newbie friendliness 90/100
Maintainers usually reply within 2 days
-
status/accepted
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
microsoft/apm#3259 · 1 comment ·
Maintainers usually reply within 2 days
Similar issues
-
Edit tool converts CRLF files to LFPossibly taken @RaphaelFakhri claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
huggingface/tau#774 ·
Maintainers usually reply within 1 day
-
show ignores the row limit when a column or table name contains "limit"Possibly taken @RaphaelFakhri claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
Maintainers usually reply within 2 days
-
documentation good first issue
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
eclipse-score/inc_someip_gateway#356 ·
Maintainers usually reply within 2 days