{
  "schemaVersion": 1,
  "skillIds": [
    "anthropic-mcp-builder",
    "anthropic-slack-gif-creator"
  ],
  "title": "IonBin Skills expansion helper probe harness",
  "reviewedOn": "2026-10-19",
  "scope": "Original IonBin harness and source-identity metadata only; no upstream skill code included",
  "commands": [
    "python -B helper_probe.py --sources <retrieved-skills-directory> --runtime-libs <existing-bundled-site-packages>"
  ],
  "requirements": [
    "Python 3.12; existing Pillow 12.3.0 and numpy 2.3.5",
    "Retrieve only the three Apache-2.0 executable files named by helper_probe.py at the pinned revision; verify bytes against helper-source-manifest.json",
    "PPTX and XLSX entries are source-only and never imported by this harness"
  ],
  "limitations": [
    "One bounded pass at one pinned revision; no model-effectiveness baseline, repeated trials, security certification or assurance about future versions.",
    "No private files, credentials, authenticated accounts, paid requests or real customer workflows. Transitive dependencies and current vulnerability advisories were not audited.",
    "MCP provider, transport and asynchronous thread dispatch are simulated; no model, protocol or network test"
  ],
  "files": [
    {
      "path": "helper_probe.py",
      "sha256": "bd0a57cd55d838c27088eab6ae169fc3d302001dbd36456aa6e77093839a1360",
      "content": "\"\"\"Original IonBin probes for two Apache-2.0 helper sets, never a live API workflow.\n\nUsage: python helper_probe.py --sources downloads/skills --runtime-libs <site-packages>\nPinned source bytes must be retrieved separately; no upstream code is bundled here.\nPPTX/XLSX helpers are deliberately not imported or executed.\n\"\"\"\nimport argparse\nimport asyncio\nimport contextlib\nimport hashlib\nimport importlib.util\nimport io\nimport json\nimport os\nfrom pathlib import Path\nimport platform\nimport subprocess\nimport sys\nfrom types import ModuleType, SimpleNamespace\n\nROOT = Path(__file__).resolve().parent.parent\nCASES = []\n\n\ndef record(case_id, expectation, passed, observed, mode='actual-helper'):\n    CASES.append(dict(id=case_id, mode=mode, expectation=expectation,\n                      passed=bool(passed), observed=observed))\n\n\ndef load(name, path):\n    spec = importlib.util.spec_from_file_location(name, path)\n    module = importlib.util.module_from_spec(spec)\n    sys.modules[name] = module\n    spec.loader.exec_module(module)\n    return module\n\n\ndef guard_process(fixtures):\n    # Application guard for inspected Python code. This is not an OS sandbox.\n    def guard(event, args):\n        if event in ('socket.connect', 'socket.bind', 'socket.getaddrinfo', 'subprocess.Popen', 'os.system'):\n            raise PermissionError('Network and child-process effects disabled')\n        if event == 'open' and isinstance(args[0], (str, bytes, os.PathLike)):\n            path = Path(os.fsdecode(args[0])).resolve()\n            mode, flags = str(args[1] or ''), args[2]\n            if any(c in mode for c in 'wax+') or (flags & (os.O_WRONLY | os.O_RDWR | os.O_CREAT | os.O_TRUNC)):\n                if not path.is_relative_to(fixtures):\n                    raise PermissionError('Write outside disposable fixtures disabled')\n        if event in ('os.remove', 'os.rmdir', 'os.mkdir', 'os.rename'):\n            for value in args[:2] if event == 'os.rename' else args[:1]:\n                if isinstance(value, (str, bytes, os.PathLike)) and not Path(os.fsdecode(value)).resolve().is_relative_to(fixtures):\n                    raise PermissionError('Filesystem mutation outside disposable fixtures disabled')\n    sys.addaudithook(guard)\n\n\ndef gif_suite(sources, fixtures):\n    from PIL import Image\n    composer = load('ionbin_frame_composer', sources / 'slack-gif-creator/core/frame_composer.py')\n    validator = load('ionbin_gif_validator', sources / 'slack-gif-creator/core/validators.py')\n    frame = composer.create_blank_frame(128, 128, (255, 255, 255))\n    composer.draw_circle(frame, (64, 64), 20, (0, 128, 255))\n    frame.save(fixtures / 'frame.png')\n    with Image.open(fixtures / 'frame.png') as reopened:\n        record('gif-frame-pixels', 'Persist the requested frame size, center fill and untouched background',\n               reopened.size == (128, 128) and reopened.getpixel((64, 64)) == (0, 128, 255) and reopened.getpixel((0, 0)) == (255, 255, 255),\n               {'dimensions': list(reopened.size), 'centerPixel': list(reopened.getpixel((64, 64))), 'cornerPixel': list(reopened.getpixel((0, 0)))})\n    frames = [Image.new('RGB', (128, 128), c) for c in ('red', 'blue')]\n    frames[0].save(fixtures / 'two.gif', save_all=True, append_images=frames[1:], duration=100, loop=0)\n    ok, info = validator.validate_gif(fixtures / 'two.gif', verbose=False)\n    record('gif-nominal-validator', 'Read two GIF frames, 128-pixel square dimensions and 0.2-second duration',\n           ok and info['frame_count'] == 2 and info['duration_seconds'] == 0.2,\n           {k: info[k] for k in ('passes', 'frame_count', 'width', 'height', 'duration_seconds')})\n    Image.new('RGB', (80, 100), 'red').save(fixtures / 'wrong-size.gif')\n    ok, info = validator.validate_gif(fixtures / 'wrong-size.gif', verbose=False)\n    record('gif-dimensions-rejected', 'Reject a nonsquare emoji image', not ok,\n           {'accepted': ok, 'width': info['width'], 'height': info['height']})\n    (fixtures / 'malformed.gif').write_bytes(b'not an image')\n    ok, info = validator.validate_gif(fixtures / 'malformed.gif', verbose=False)\n    record('gif-malformed-rejected', 'Reject a malformed image without reporting it ready', not ok and 'error' in info,\n           {'accepted': ok, 'errorReturned': 'error' in info})\n    ok, info = validator.validate_gif(fixtures / 'frame.png', verbose=False)\n    record('gif-format-enforced', 'Require GIF format when validating a file as a GIF', not ok,\n           {'actualFormat': 'PNG', 'accepted': ok, 'frameCount': info.get('frame_count')})\n    frames[0].save(fixtures / 'long.gif', save_all=True, append_images=frames[1:], duration=2000, loop=0)\n    ok, info = validator.validate_gif(fixtures / 'long.gif', verbose=False)\n    record('gif-duration-enforced', 'Reject an emoji animation beyond the skill\\'s under-three-second guidance', not ok,\n           {'accepted': ok, 'reportedSeconds': info.get('duration_seconds'), 'guidanceLimitSeconds': 3})\n    (fixtures / 'oversized.gif').write_bytes((fixtures / 'two.gif').read_bytes() + b'\\0' * (6 * 1024 * 1024))\n    ok, info = validator.validate_gif(fixtures / 'oversized.gif', verbose=False)\n    record('gif-size-enforced', 'Make the ready result false for a GIF exceeding the helper\\'s five-MiB warning threshold', not ok,\n           {'accepted': ok, 'bytes': (fixtures / 'oversized.gif').stat().st_size, 'warningThresholdMiB': 5, 'fixtureMethod': 'Valid tiny GIF with six MiB of trailing zero padding; not a resource exhaustion test'})\n    frames[0].save(fixtures / 'variable.gif', save_all=True, append_images=frames[1:], duration=[100, 900], loop=0)\n    ok, info = validator.validate_gif(fixtures / 'variable.gif', verbose=False)\n    with Image.open(fixtures / 'variable.gif') as reopened:\n        durations = []\n        for i in range(reopened.n_frames):\n            reopened.seek(i); durations.append(reopened.info['duration'])\n    record('gif-variable-duration', 'Sum actual per-frame durations for an unevenly timed GIF', info['duration_seconds'] == sum(durations) / 1000,\n           {'frameDurationsMs': durations, 'expectedSeconds': sum(durations) / 1000, 'reportedSeconds': info['duration_seconds']})\n\n\ndef mcp_suite(sources, fixtures):\n    # Missing API/transport SDK imports are replaced with non-networking sentinels.\n    # Pure upstream functions and agent-loop control flow still run unchanged.\n    provider = ModuleType('anthropic')\n    class NeverClient:\n        def __init__(self, *args, **kwargs):\n            raise PermissionError('Real API client prohibited')\n    provider.Anthropic = NeverClient\n    transport = ModuleType('connections')\n    def never_connection(*args, **kwargs):\n        raise PermissionError('Real MCP transport prohibited')\n    transport.create_connection = never_connection\n    sys.modules['anthropic'], sys.modules['connections'] = provider, transport\n    evaluator = load('ionbin_mcp_evaluator', sources / 'mcp-builder/scripts/evaluation.py')\n    # Windows asyncio's wakeup socket conflicts with the no-sockets guard.\n    # Replace only to_thread dispatch and drive immediately completing fake calls.\n    # This tests control flow, not thread scheduling, cancellation or transport.\n    async def immediate_thread(func, *args, **kwargs):\n        return func(*args, **kwargs)\n    evaluator.asyncio.to_thread = immediate_thread\n    def run_immediate(coro):\n        try:\n            coro.send(None)\n        except StopIteration as finished:\n            return finished.value\n        finally:\n            coro.close()\n        raise RuntimeError('Unexpected asynchronous I/O in in-memory fixture')\n    fixture = fixtures / 'questions.xml'\n    fixture.write_text('<evaluation><qa_pair><question> What is 2 + 2? </question><answer> 4 </answer></qa_pair></evaluation>', encoding='utf-8')\n    parsed = evaluator.parse_evaluation_file(fixture)\n    record('mcp-xml-nominal', 'Parse and trim one synthetic question and answer pair', parsed == [{'question': 'What is 2 + 2?', 'answer': '4'}], {'pairs': parsed})\n    fixture.write_text('<evaluation><qa_pair>', encoding='utf-8')\n    with contextlib.redirect_stdout(io.StringIO()) as diagnostic:\n        parsed = evaluator.parse_evaluation_file(fixture)\n    record('mcp-xml-malformed', 'Return no tasks and a diagnostic for malformed XML', parsed == [] and 'Error parsing' in diagnostic.getvalue(), {'taskCount': len(parsed), 'parseErrorReported': 'Error parsing' in diagnostic.getvalue()})\n    with contextlib.redirect_stdout(io.StringIO()) as diagnostic:\n        headers = evaluator.parse_headers(['Authorization SYNTHETIC_SECRET_MARKER'])\n    record('mcp-malformed-header-redaction', 'Avoid copying a malformed credential-like header into logs', 'SYNTHETIC_SECRET_MARKER' not in diagnostic.getvalue(), {'headerCount': len(headers), 'syntheticMarkerEchoed': 'SYNTHETIC_SECRET_MARKER' in diagnostic.getvalue()})\n\n    class FakeClient:\n        def __init__(self, responses):\n            self.responses = iter(responses); self.calls = []; self.messages = SimpleNamespace(create=self.create)\n        def create(self, **kwargs):\n            self.calls.append(kwargs)\n            return next(self.responses)\n    class FakeConnection:\n        def __init__(self, fail=False): self.calls = []; self.fail = fail\n        async def call_tool(self, name, args):\n            self.calls.append({'name': name, 'args': args})\n            if self.fail: raise ValueError('SYNTHETIC_INTERNAL_MARKER')\n            return {'value': 4}\n    def tool(i): return SimpleNamespace(type='tool_use', id=f'tool-{i}', name=f'fixture_{i}', input={'x': 2})\n    def response(blocks, reason): return SimpleNamespace(content=blocks, stop_reason=reason)\n    final = response([SimpleNamespace(type='text', text='<response>4</response>')], 'end_turn')\n    for name, count, fail in [('single', 1, False), ('multiple', 2, False), ('exception', 1, True)]:\n        client = FakeClient([response([tool(i) for i in range(count)], 'tool_use'), final])\n        connection = FakeConnection(fail)\n        answer, metrics = run_immediate(evaluator.agent_loop(client, 'synthetic-model', 'Synthetic task', [], connection))\n        results = [m for m in client.calls[-1]['messages'] if m['role'] == 'user' and isinstance(m['content'], list)]\n        result_text = '\\n'.join(str(m['content'][0]['content']) for m in results)\n        if name == 'single':\n            record('mcp-single-tool-loop', 'Run one fake tool call and recover the final answer', len(connection.calls) == 1 and answer == '<response>4</response>' and metrics['fixture_0']['count'] == 1,\n                   {'toolCalls': len(connection.calls), 'providerCalls': len(client.calls), 'finalAnswer': answer, 'realProviderCalls': 0, 'realMcpCalls': 0}, 'mocked-provider-and-transport')\n        elif name == 'multiple':\n            record('mcp-multiple-tool-loop', 'Answer every tool-use block in a two-tool model response', len(connection.calls) == 2,\n                   {'requestedToolCalls': count, 'executedFakeToolCalls': len(connection.calls), 'toolResultBlocks': len(results)}, 'mocked-provider-and-transport')\n        else:\n            record('mcp-exception-redaction', 'Keep internal exception details and stack traces out of model-bound tool results', 'SYNTHETIC_INTERNAL_MARKER' not in result_text and 'Traceback' not in result_text,\n                   {'syntheticInternalMarkerForwarded': 'SYNTHETIC_INTERNAL_MARKER' in result_text, 'tracebackForwarded': 'Traceback' in result_text, 'realProviderCalls': 0}, 'mocked-provider-and-transport')\n\n\ndef main():\n    parser = argparse.ArgumentParser()\n    parser.add_argument('--sources', type=Path, required=True)\n    parser.add_argument('--runtime-libs', type=Path, required=True)\n    parser.add_argument('--suite', choices=['gif', 'mcp'])\n    args = parser.parse_args()\n    sources = args.sources.resolve()\n    manifest = json.loads((Path(__file__).parent / 'helper-source-manifest.json').read_text(encoding='utf-8'))\n    executable = {'skills/slack-gif-creator/core/frame_composer.py', 'skills/slack-gif-creator/core/validators.py', 'skills/mcp-builder/scripts/evaluation.py'}\n    for entry in manifest:\n        if entry['path'] in executable:\n            source_file = sources / entry['path'].removeprefix('skills/')\n            if hashlib.sha256(source_file.read_bytes()).hexdigest() != entry['sha256']:\n                raise ValueError('Pinned source hash mismatch')\n            executable.remove(entry['path'])\n    if executable:\n        raise ValueError('Missing source hash')\n    run = ROOT / 'runs' / 'helpers'\n    run.mkdir(parents=True, exist_ok=True)\n    if args.suite:\n        sys.path.append(str(args.runtime_libs.resolve()))\n        sys.dont_write_bytecode = True\n        fixtures = run / args.suite\n        fixtures.mkdir(parents=True, exist_ok=True)\n        guard_process(fixtures)\n        globals()[args.suite + '_suite'](sources, fixtures)\n        print(json.dumps({'suite': args.suite, 'cases': CASES}))\n        return\n    for folder in ('home', 'temp'): (run / folder).mkdir(exist_ok=True)\n    env = {k: os.environ[k] for k in ('SystemRoot', 'WINDIR', 'COMSPEC') if k in os.environ}\n    env.update(PATH=str(Path(sys.executable).parent), TEMP=str(run / 'temp'), TMP=str(run / 'temp'), HOME=str(run / 'home'), USERPROFILE=str(run / 'home'), PYTHONIOENCODING='utf-8', PYTHONDONTWRITEBYTECODE='1')\n    results = []\n    for suite in ('gif', 'mcp'):\n        proc = subprocess.run([sys.executable, '-B', str(Path(__file__).resolve()), '--sources', str(sources), '--runtime-libs', str(args.runtime_libs.resolve()), '--suite', suite], env=env, cwd=run, capture_output=True, text=True, encoding='utf-8', timeout=30)\n        if proc.returncode:\n            (run / f'{suite}-setup-error.txt').write_text(proc.stderr, encoding='utf-8')\n            raise RuntimeError(f'{suite} suite setup failed; see local diagnostic')\n        result = json.loads(proc.stdout.strip().splitlines()[-1])\n        result['exitCode'] = proc.returncode\n        results.append(result)\n    output = {'python': platform.python_version(), 'os': platform.platform(), 'suites': results}\n    (run / 'observations.json').write_text(json.dumps(output, indent=2), encoding='utf-8')\n    print(json.dumps({r['suite']: {'passed': sum(c['passed'] for c in r['cases']), 'total': len(r['cases'])} for r in results}))\n\n\nif __name__ == '__main__':\n    main()\n"
    },
    {
      "path": "helper-source-manifest.json",
      "sha256": "451463dcf8c938797d0e893774d9826425f441af74a1d636a8aafe6875bff928",
      "content": "[\r\n  {\r\n    \"path\": \"skills/pptx/SKILL.md\",\r\n    \"sha256\": \"a7ff03e2c85b636f55232a6b1555f5dd90216b7a1a359ab289d8364e6acbc6a0\",\r\n    \"gitBlob\": \"41cd2306977f269bb1d8169a9643b35053aa66bd\",\r\n    \"sourceUrl\": \"https://github.com/anthropics/skills/blob/dbd4588f9e1033efb41dad4bef2f7947c8993d44/skills/pptx/SKILL.md\"\r\n  },\r\n  {\r\n    \"path\": \"skills/pptx/LICENSE.txt\",\r\n    \"sha256\": \"79f6d8f5b427252fa3b1c11ecdbdb6bf610b944f7530b4de78f770f38741cfaa\",\r\n    \"gitBlob\": \"c55ab42224874608473643de0a85736b7fec0730\",\r\n    \"sourceUrl\": \"https://github.com/anthropics/skills/blob/dbd4588f9e1033efb41dad4bef2f7947c8993d44/skills/pptx/LICENSE.txt\"\r\n  },\r\n  {\r\n    \"path\": \"skills/pptx/scripts/add_slide.py\",\r\n    \"sha256\": \"3922f819ee1f6b8bdc6aa146d1a86de70640f5f919321fe3f01a764482ff69c9\",\r\n    \"gitBlob\": \"f013ea94d1785c8cf767fb69284ffb5b8dd9d390\",\r\n    \"sourceUrl\": \"https://github.com/anthropics/skills/blob/dbd4588f9e1033efb41dad4bef2f7947c8993d44/skills/pptx/scripts/add_slide.py\"\r\n  },\r\n  {\r\n    \"path\": \"skills/pptx/scripts/clean.py\",\r\n    \"sha256\": \"5c808cd4dff7e02661ef3c68b5917f4e25097cc6610c92a3a7df4a6366a5c3c1\",\r\n    \"gitBlob\": \"551dd23192f6eae8e79d4b59b08a3cd9d10feadd\",\r\n    \"sourceUrl\": \"https://github.com/anthropics/skills/blob/dbd4588f9e1033efb41dad4bef2f7947c8993d44/skills/pptx/scripts/clean.py\"\r\n  },\r\n  {\r\n    \"path\": \"skills/pptx/scripts/office/helpers/__init__.py\",\r\n    \"sha256\": \"678e42456d9e10923c8b9a93691cdd993de3433448a184fa72a0c31f4ae086d5\",\r\n    \"gitBlob\": \"d3c5817c7e50b23bdd82032c8f89fed497bce9fa\",\r\n    \"sourceUrl\": \"https://github.com/anthropics/skills/blob/dbd4588f9e1033efb41dad4bef2f7947c8993d44/skills/pptx/scripts/office/helpers/__init__.py\"\r\n  },\r\n  {\r\n    \"path\": \"skills/pptx/scripts/office/helpers/pptx_slide.py\",\r\n    \"sha256\": \"7b9f69b4a5bd6a2d9eabf9e0e3e796d7a421373145f6a8cd11f60b7ba2d6a5d0\",\r\n    \"gitBlob\": \"22f9aee0ff6c4797fa344f064d7cd6a1ab96b05b\",\r\n    \"sourceUrl\": \"https://github.com/anthropics/skills/blob/dbd4588f9e1033efb41dad4bef2f7947c8993d44/skills/pptx/scripts/office/helpers/pptx_slide.py\"\r\n  },\r\n  {\r\n    \"path\": \"skills/pptx/scripts/office/soffice.py\",\r\n    \"sha256\": \"df2c8d7249c132a4512d744482e4b5ed0ecbe885f0bcfb1295e7e6a7ced0432c\",\r\n    \"gitBlob\": \"0b4c99deca54013c550458c9244ee63eea748dca\",\r\n    \"sourceUrl\": \"https://github.com/anthropics/skills/blob/dbd4588f9e1033efb41dad4bef2f7947c8993d44/skills/pptx/scripts/office/soffice.py\"\r\n  },\r\n  {\r\n    \"path\": \"skills/pptx/scripts/thumbnail.py\",\r\n    \"sha256\": \"94ef83a84346aa2d63913de0d42bb2fe902ccdc17bfac6130096ca758381793c\",\r\n    \"gitBlob\": \"d49cac0e1a138fd0cbf46dece32b0da153cdc4f7\",\r\n    \"sourceUrl\": \"https://github.com/anthropics/skills/blob/dbd4588f9e1033efb41dad4bef2f7947c8993d44/skills/pptx/scripts/thumbnail.py\"\r\n  },\r\n  {\r\n    \"path\": \"skills/xlsx/SKILL.md\",\r\n    \"sha256\": \"6712b39718fe815054abca9c3ee72f989613e6f771c8a5c58f30a65a6c905622\",\r\n    \"gitBlob\": \"9da54804cc8c938586f89363c8da3b3a6e2a563d\",\r\n    \"sourceUrl\": \"https://github.com/anthropics/skills/blob/dbd4588f9e1033efb41dad4bef2f7947c8993d44/skills/xlsx/SKILL.md\"\r\n  },\r\n  {\r\n    \"path\": \"skills/xlsx/LICENSE.txt\",\r\n    \"sha256\": \"79f6d8f5b427252fa3b1c11ecdbdb6bf610b944f7530b4de78f770f38741cfaa\",\r\n    \"gitBlob\": \"c55ab42224874608473643de0a85736b7fec0730\",\r\n    \"sourceUrl\": \"https://github.com/anthropics/skills/blob/dbd4588f9e1033efb41dad4bef2f7947c8993d44/skills/xlsx/LICENSE.txt\"\r\n  },\r\n  {\r\n    \"path\": \"skills/xlsx/scripts/recalc.py\",\r\n    \"sha256\": \"66f6e726d5a53cfabea0b6471d6669deb95e54e96cb7913b687e4388da1bb3d9\",\r\n    \"gitBlob\": \"6232be2deea56cc97c1d8996e4d68adf2457059c\",\r\n    \"sourceUrl\": \"https://github.com/anthropics/skills/blob/dbd4588f9e1033efb41dad4bef2f7947c8993d44/skills/xlsx/scripts/recalc.py\"\r\n  },\r\n  {\r\n    \"path\": \"skills/xlsx/scripts/office/soffice.py\",\r\n    \"sha256\": \"df2c8d7249c132a4512d744482e4b5ed0ecbe885f0bcfb1295e7e6a7ced0432c\",\r\n    \"gitBlob\": \"0b4c99deca54013c550458c9244ee63eea748dca\",\r\n    \"sourceUrl\": \"https://github.com/anthropics/skills/blob/dbd4588f9e1033efb41dad4bef2f7947c8993d44/skills/xlsx/scripts/office/soffice.py\"\r\n  },\r\n  {\r\n    \"path\": \"skills/mcp-builder/SKILL.md\",\r\n    \"sha256\": \"0f4592dcb53cf2b5d6b7febee6b4152018b565551a1c29e3c612f57b218ab295\",\r\n    \"gitBlob\": \"8a1a77a47d141967b246adb4da4f91037578ff7d\",\r\n    \"sourceUrl\": \"https://github.com/anthropics/skills/blob/dbd4588f9e1033efb41dad4bef2f7947c8993d44/skills/mcp-builder/SKILL.md\"\r\n  },\r\n  {\r\n    \"path\": \"skills/mcp-builder/LICENSE.txt\",\r\n    \"sha256\": \"bc6b3af2f331cbc7fb0da1344efb2cbe5877a31498b4d70dbc7000f3405a1362\",\r\n    \"gitBlob\": \"4f881c52d1f72f4cfb720e339e2d35c3058d01a9\",\r\n    \"sourceUrl\": \"https://github.com/anthropics/skills/blob/dbd4588f9e1033efb41dad4bef2f7947c8993d44/skills/mcp-builder/LICENSE.txt\"\r\n  },\r\n  {\r\n    \"path\": \"skills/mcp-builder/scripts/connections.py\",\r\n    \"sha256\": \"9403668a2041568772082a8b334122c1f88daf0541fb393af4522d0094a47a6e\",\r\n    \"gitBlob\": \"ffcd0da3fbe1539320d022017ae83b61a9587a5c\",\r\n    \"sourceUrl\": \"https://github.com/anthropics/skills/blob/dbd4588f9e1033efb41dad4bef2f7947c8993d44/skills/mcp-builder/scripts/connections.py\"\r\n  },\r\n  {\r\n    \"path\": \"skills/mcp-builder/scripts/evaluation.py\",\r\n    \"sha256\": \"49ed1d17cdce5da101b210197740713f49b935c29d4f339542a14b132658e6f7\",\r\n    \"gitBlob\": \"41778569c45a458e0eea839b8917692ad65be2d5\",\r\n    \"sourceUrl\": \"https://github.com/anthropics/skills/blob/dbd4588f9e1033efb41dad4bef2f7947c8993d44/skills/mcp-builder/scripts/evaluation.py\"\r\n  },\r\n  {\r\n    \"path\": \"skills/mcp-builder/scripts/requirements.txt\",\r\n    \"sha256\": \"d5d7558b2368ecea9dfeed7d1fbc71ee9e0750bebd1282faa527d528a344c3c7\",\r\n    \"gitBlob\": \"e73e5d1e356edafadb9dc9243e6f300f2c5529b3\",\r\n    \"sourceUrl\": \"https://github.com/anthropics/skills/blob/dbd4588f9e1033efb41dad4bef2f7947c8993d44/skills/mcp-builder/scripts/requirements.txt\"\r\n  },\r\n  {\r\n    \"path\": \"skills/mcp-builder/reference/mcp_best_practices.md\",\r\n    \"sha256\": \"80fb4369a349447cf18ecdd7494fe7938b6065377e9f08c077cec411093a3007\",\r\n    \"gitBlob\": \"b9d343cc3ae89b1fc139dae96bdb2b7e29ba3648\",\r\n    \"sourceUrl\": \"https://github.com/anthropics/skills/blob/dbd4588f9e1033efb41dad4bef2f7947c8993d44/skills/mcp-builder/reference/mcp_best_practices.md\"\r\n  },\r\n  {\r\n    \"path\": \"skills/slack-gif-creator/SKILL.md\",\r\n    \"sha256\": \"2efca615ce55a3edd8fc05c779068a8085816617991987e446606403cd3abb22\",\r\n    \"gitBlob\": \"16660d8ceb77af47986bba1c9176c2ff3f287a91\",\r\n    \"sourceUrl\": \"https://github.com/anthropics/skills/blob/dbd4588f9e1033efb41dad4bef2f7947c8993d44/skills/slack-gif-creator/SKILL.md\"\r\n  },\r\n  {\r\n    \"path\": \"skills/slack-gif-creator/LICENSE.txt\",\r\n    \"sha256\": \"bc6b3af2f331cbc7fb0da1344efb2cbe5877a31498b4d70dbc7000f3405a1362\",\r\n    \"gitBlob\": \"4f881c52d1f72f4cfb720e339e2d35c3058d01a9\",\r\n    \"sourceUrl\": \"https://github.com/anthropics/skills/blob/dbd4588f9e1033efb41dad4bef2f7947c8993d44/skills/slack-gif-creator/LICENSE.txt\"\r\n  },\r\n  {\r\n    \"path\": \"skills/slack-gif-creator/core/gif_builder.py\",\r\n    \"sha256\": \"b6f50d738c491ee0438a2e86e897f71cdab9792494ba4605f140befb0bddbf89\",\r\n    \"gitBlob\": \"5759f144fe3cef50f3dfd3b8911e612e80099cea\",\r\n    \"sourceUrl\": \"https://github.com/anthropics/skills/blob/dbd4588f9e1033efb41dad4bef2f7947c8993d44/skills/slack-gif-creator/core/gif_builder.py\"\r\n  },\r\n  {\r\n    \"path\": \"skills/slack-gif-creator/core/validators.py\",\r\n    \"sha256\": \"56bd19e3aae05f8387d78ec8185d6098b3dc909d1fa041211753da37212528a3\",\r\n    \"gitBlob\": \"a6f5bdf28ddd0a9613f2e076e37d940e03ad997c\",\r\n    \"sourceUrl\": \"https://github.com/anthropics/skills/blob/dbd4588f9e1033efb41dad4bef2f7947c8993d44/skills/slack-gif-creator/core/validators.py\"\r\n  },\r\n  {\r\n    \"path\": \"skills/slack-gif-creator/core/frame_composer.py\",\r\n    \"sha256\": \"a127ea8f2a58893ea10a5c7b5cab4e2010af6515adc538676eb0cc14f5a03985\",\r\n    \"gitBlob\": \"1afe434811bd4a8a1bdb4df7961147f2c9afd130\",\r\n    \"sourceUrl\": \"https://github.com/anthropics/skills/blob/dbd4588f9e1033efb41dad4bef2f7947c8993d44/skills/slack-gif-creator/core/frame_composer.py\"\r\n  },\r\n  {\r\n    \"path\": \"skills/slack-gif-creator/core/easing.py\",\r\n    \"sha256\": \"60bc943449802541f0f0881a874faa7ef408aaaf0b758fde756664ada7740452\",\r\n    \"gitBlob\": \"772fa830235dac37ba995ee66778111f59c2ee31\",\r\n    \"sourceUrl\": \"https://github.com/anthropics/skills/blob/dbd4588f9e1033efb41dad4bef2f7947c8993d44/skills/slack-gif-creator/core/easing.py\"\r\n  },\r\n  {\r\n    \"path\": \"skills/slack-gif-creator/requirements.txt\",\r\n    \"sha256\": \"edc7108a0c6b56183566c71ee96830f6dc791e3b41952112d9cb56b33a6bd757\",\r\n    \"gitBlob\": \"8bc4493e9163cb513d4be38ab9fe5c1ff763e0d7\",\r\n    \"sourceUrl\": \"https://github.com/anthropics/skills/blob/dbd4588f9e1033efb41dad4bef2f7947c8993d44/skills/slack-gif-creator/requirements.txt\"\r\n  }\r\n]\r\n"
    }
  ]
}
