> ## Documentation Index
> Fetch the complete documentation index at: https://docs.modulex.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Contributing

> Ways to contribute to ModuleX — build and submit a new integration, improve the docs, report bugs, and share feedback — plus the community expectations everyone is asked to follow.

export const MediaEmbed = ({id, type = 'screenshot', caption = '', ext, ratio = '16 / 9'}) => {
  const isVideo = type === 'video' || type === 'app_video';
  const resolvedExt = ext || (isVideo ? 'mp4' : type === 'screenshot' ? 'webp' : 'svg');
  const src = 'https://media.modulex.dev/' + id + '.' + resolvedExt;
  const [status, setStatus] = useState('loading');
  const [isDev, setIsDev] = useState(false);
  const [inView, setInView] = useState(false);
  const boxRef = useRef(null);
  useEffect(() => {
    if (typeof window === 'undefined') return;
    const h = window.location.hostname;
    setIsDev(h === 'localhost' || h === '127.0.0.1' || h.endsWith('.mintlify.app'));
  }, []);
  useEffect(() => {
    if (inView) return;
    if (typeof IntersectionObserver === 'undefined') {
      setInView(true);
      return;
    }
    const el = boxRef.current;
    if (!el) return;
    const io = new IntersectionObserver(entries => {
      if (entries.some(e => e.isIntersecting)) {
        setInView(true);
        io.disconnect();
      }
    }, {
      rootMargin: '300px'
    });
    io.observe(el);
    return () => io.disconnect();
  }, [inView]);
  if (status === 'missing') {
    if (!isDev) return null;
    return <div style={{
      display: 'flex',
      flexDirection: 'column',
      justifyContent: 'center',
      gap: '0.4rem',
      padding: '1rem 1.25rem',
      margin: '1.25rem 0',
      width: '100%',
      aspectRatio: ratio,
      boxSizing: 'border-box',
      border: '1px dashed rgba(128,128,128,0.45)',
      borderRadius: '0.75rem',
      background: 'rgba(128,128,128,0.06)',
      color: 'currentColor',
      fontSize: '0.85rem',
      lineHeight: 1.45
    }}>
        <div style={{
      display: 'flex',
      alignItems: 'center',
      gap: '0.5rem',
      opacity: 0.75
    }}>
          <span aria-hidden="true">🎬</span>
          <code style={{
      fontSize: '0.75rem'
    }}>{id}</code>
          <span style={{
      fontSize: '0.65rem',
      textTransform: 'uppercase',
      letterSpacing: '0.04em',
      padding: '0.1rem 0.4rem',
      borderRadius: '0.4rem',
      background: 'rgba(128,128,128,0.18)'
    }}>
            {type}
          </span>
        </div>
        <div style={{
      opacity: 0.9
    }}>{caption || 'Media not uploaded yet.'}</div>
        <div style={{
      fontSize: '0.7rem',
      opacity: 0.5
    }}>
          Upload to R2 as <code>{id}.{resolvedExt}</code> — preview only, hidden in production.
        </div>
      </div>;
  }
  const mediaStyle = {
    display: status === 'loaded' ? 'block' : 'none',
    width: '100%',
    height: 'auto',
    borderRadius: '0.75rem'
  };
  const media = isVideo ? <video src={inView ? src : undefined} autoPlay loop muted playsInline preload="metadata" onLoadedData={() => setStatus('loaded')} onError={() => setStatus('missing')} style={mediaStyle} /> : <img src={inView ? src : undefined} alt={caption} onLoad={() => setStatus('loaded')} onError={() => setStatus('missing')} style={mediaStyle} />;
  return <figure style={{
    margin: '1.25rem 0'
  }}>
      <div ref={boxRef} style={status === 'loaded' ? {
    width: '100%'
  } : {
    width: '100%',
    aspectRatio: ratio,
    borderRadius: '0.75rem',
    background: 'rgba(128,128,128,0.06)'
  }}>
        {media}
      </div>
      {status === 'loaded' && caption ? <figcaption style={{
    marginTop: '0.5rem',
    textAlign: 'center',
    fontSize: '0.85rem',
    opacity: 0.7
  }}>
          {caption}
        </figcaption> : null}
    </figure>;
};

ModuleX gets better when people who use it pitch in. Whether you want to add a brand-new integration, fix a typo you spotted in these docs, file a bug, or just tell us what would make your day easier, there is a place for your contribution. This page shows you the options and how to get started with each one.

You do not need to be a developer to help. Some of the most valuable contributions are a clear bug report or a sentence that makes a confusing page easier to read.

## Ways to contribute

<CardGroup cols={2}>
  <Card title="Build an integration" icon="puzzle-piece" href="/integrations/building/overview">
    Add support for a service ModuleX does not connect to yet. This is the most impactful contribution — every new integration unlocks more tools for everyone.
  </Card>

  <Card title="Improve the docs" icon="pen-to-square">
    Fix a typo, clarify a step, or flag something that is out of date. Small edits add up to a much better reading experience.
  </Card>

  <Card title="Report a bug" icon="bug">
    Tell us when something does not work as described. A good bug report is one of the fastest ways to get a fix shipped.
  </Card>

  <Card title="Share feedback" icon="comment">
    Suggest a feature, describe a workflow you wish were easier, or tell us what you love. Product direction is shaped by what we hear.
  </Card>
</CardGroup>

<Note>
  ModuleX is developed on GitHub under the [`ModuleXAI`](https://github.com/ModuleXAI) organization. The public integration catalog lives in the [`modulex-integrations`](https://github.com/ModuleXAI/modulex-integrations) repository, which is where most code contributions happen.
</Note>

## Building integrations

An integration is a connector to an external service — for example GitHub, Slack, or a database. Each integration exposes one or more **tools**, the individual actions that a [workflow](/concepts/workflows-and-runs), the [AI Composer](/concepts/ai-composer), and the [Assistant](/assistant/overview) can call. Adding an integration is the highest-leverage way to contribute, because the new tools become available to every ModuleX user.

Integrations are authored as Python packages in the open-source [`modulex-integrations`](https://github.com/ModuleXAI/modulex-integrations) repository. The full author's guide — directory layout, the manifest, the `@tool` function contract, registering the entry point, and testing locally — lives on the [build an integration](/integrations/building/overview) page. Here is the shape of the work.

<Steps>
  <Step title="Pick a name and copy an existing tool">
    Choose a lowercase, snake-case name for your integration (for example `acme`). Copy a similar folder under `src/modulex_integrations/tools/` — `github` for a token-auth REST API, or `exa` for an API-key service — and edit it for your service. Every integration ships the same fixed file set, so reviews are mechanical.
  </Step>

  <Step title="Write the manifest, tools, outputs, and tests">
    Fill in `manifest.py` (the integration's identity, actions, and how it authenticates), `tools.py` (one `@tool` function per action), `outputs.py` (the typed result models), and at least one happy-path test per tool. The full contracts are documented in the [manifest and schema contract](/integrations/building/manifest-schema) and the [@tool function contract](/integrations/building/tool-contract).
  </Step>

  <Step title="Register the entry point">
    Add one line to the root `pyproject.toml` under `[project.entry-points."modulex.tools"]` so the runtime can discover your integration. Without this line the runtime will not load your tool, even though it appears on disk.
  </Step>

  <Step title="Run the checks and open a pull request">
    Run the tests, the linter, and the type checker locally, then open a pull request against `modulex-integrations`. Reviewers confirm the contracts hold and that your integration follows the same patterns as the rest of the catalog.
  </Step>
</Steps>

<CodeGroup>
  ```bash Set up the repository theme={null}
  git clone https://github.com/ModuleXAI/modulex-integrations.git
  cd modulex-integrations
  pip install -e ".[dev]"
  pytest
  ```

  ```bash Test one integration theme={null}
  pytest src/modulex_integrations/tools/acme/tests/
  ```

  ```bash Lint and type-check before you push theme={null}
  ruff check src tests
  mypy src/modulex_integrations
  ```
</CodeGroup>

<Warning>
  Do not rely on `pip install` extras to pull in a tool's dependencies. The `[all]` extra resolves to an empty list and there are no per-tool extras groups (`[github]`, `[slack]`, and the like are not defined), because the script that assembles them does not exist yet. Installing `modulex-integrations[all]` or `modulex-integrations[acme]` installs only the core package and pip will warn about the unknown extra. Until the assemble step lands, install `modulex-integrations` and then install each tool's dependencies manually. See [installing integrations](/integrations/install).
</Warning>

<MediaEmbed id="MX-MEDIA-4480" type="image" caption={"The five-stage path of contributing a new integration, from fork to live in the catalog."} />

### What reviewers look for

<AccordionGroup>
  <Accordion title="The contracts hold at import time">
    Every schema model rejects unknown fields, so a misspelled or extra manifest field fails when the module is imported. Importing the manifest — or running `pytest`, which imports it — surfaces these errors before review.
  </Accordion>

  <Accordion title="Names line up everywhere">
    The integration name must be identical across the folder name, the manifest `name`, the entry-point key, and the entry-point value. Each action name must equal a `@tool` function name listed in the `TOOLS` tuple.
  </Accordion>

  <Accordion title="One consistent error pattern">
    Pick a single way to signal failure across the integration — raise on HTTP errors, return an inline failure payload, or wrap calls in try/except — and apply it consistently. Set explicit timeouts on outbound calls.
  </Accordion>

  <Accordion title="Credentials never reach the model">
    The runtime injects credentials at call time and strips the credential fields from the schema the model sees. Follow the auth conventions in the [@tool function contract](/integrations/building/tool-contract) so tokens are never exposed to the language model.
  </Accordion>
</AccordionGroup>

<Card title="Start building" icon="hammer" href="/integrations/building/overview">
  The complete, step-by-step guide to authoring an integration end to end.
</Card>

## Documentation and feedback

These docs are a living document. If a page is confusing, out of date, or missing something you needed, telling us is a real contribution.

<CardGroup cols={2}>
  <Card title="Suggest a docs change" icon="file-pen">
    Spotted a typo, a broken example, or a step that no longer matches the product? Open an issue describing the page and what is wrong, or propose the fix directly.
  </Card>

  <Card title="Report a bug" icon="bug">
    Found a defect in ModuleX itself? Open an issue with the steps to reproduce, what you expected, and what happened instead.
  </Card>

  <Card title="Request a feature" icon="lightbulb">
    Describe the problem you are trying to solve, not just the solution you have in mind — it helps us find the best fit.
  </Card>

  <Card title="Ask the community" icon="discord" href="https://discord.gg/jEyCABwU9E">
    Join the ModuleX Discord to ask questions, share what you have built, and talk to other builders and the team.
  </Card>
</CardGroup>

### How to write a report we can act on

A few details turn a vague message into something we can fix quickly. When you report a bug, please include:

<Steps>
  <Step title="What you did">
    The exact steps to reproduce the problem, in order. If it involves the API, include the request (with secrets removed) and the surface it happened on.
  </Step>

  <Step title="What you expected">
    What you thought would happen.
  </Step>

  <Step title="What actually happened">
    The result you got, including any error message or status code. If you can, copy the full error rather than paraphrasing it.
  </Step>

  <Step title="Where and when">
    Whether it happened in the app, an SDK, or a direct API call; roughly when; and anything you already tried.
  </Step>
</Steps>

<Note>
  Never paste real secrets into an issue or a pull request. Redact API keys (anything starting with `mx_live_`), access tokens, and other credentials before you share logs or requests. To report a security issue privately, email `security@modulex.dev` rather than opening a public issue.
</Note>

## Community expectations

ModuleX is built by a community, and we want it to be a place where everyone is treated with respect. We ask everyone who takes part — in issues, pull requests, the Discord, and anywhere else — to follow a few simple principles.

<CardGroup cols={2}>
  <Card title="Be respectful" icon="handshake">
    Assume good intent, disagree on ideas rather than people, and keep discussion constructive.
  </Card>

  <Card title="Be welcoming" icon="users">
    People arrive with different backgrounds and levels of experience. Help newcomers and answer questions patiently.
  </Card>

  <Card title="Be clear" icon="message-check">
    Give context, share the steps you took, and keep feedback specific and actionable.
  </Card>

  <Card title="Keep it safe" icon="shield-check">
    No harassment, no sharing of others' private information, and no posting of secrets or sensitive data.
  </Card>
</CardGroup>

<Note>
  A formally published, versioned code of conduct for the ModuleX open-source repositories is not available yet. **TBD** — until one is published, the principles above describe what we expect of everyone in the community. If you experience or witness behavior that breaks them, contact the team at `contact@modulex.dev`.
</Note>

## Get help and stay current

<CardGroup cols={3}>
  <Card title="Getting help" icon="life-ring" href="/help/getting-help">
    Where to find answers and how to reach a human when you are stuck.
  </Card>

  <Card title="System status" icon="signal" href="/reference/status">
    Check current health and where to watch for incidents before reporting an outage.
  </Card>

  <Card title="Changelog" icon="clock-rotate-left" href="/reference/changelog">
    See what has changed recently across ModuleX and these docs.
  </Card>
</CardGroup>
