Back to skills
SkillHub ClubBuild BackendIntegrationBackend

activitypub-federation

This skill provides detailed documentation for implementing and understanding the ActivityPub protocol within WordPress. It covers core concepts like actors, activities, and objects, explains server-to-server federation mechanics, and offers concrete PHP implementation patterns for transformers, handlers, and third-party plugin integrations.

Packaged view

This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.

Stars
565
Hot score
99
Updated
March 20, 2026
Overall rating
A8.3
Composite score
6.9
Best-practice grade
B73.6

Install command

npx @skill-hub/cli install automattic-wordpress-activitypub-activitypub-federation
activitypubwordpressfederationprotocolsocial-web

Repository

Automattic/wordpress-activitypub

Skill path: .claude/skills/activitypub-federation

This skill provides detailed documentation for implementing and understanding the ActivityPub protocol within WordPress. It covers core concepts like actors, activities, and objects, explains server-to-server federation mechanics, and offers concrete PHP implementation patterns for transformers, handlers, and third-party plugin integrations.

Open repository

Best for

Primary workflow: Build Backend.

Technical facets: Integration, Backend.

Target audience: WordPress developers building or extending federated social features, and developers needing to understand ActivityPub implementation details..

License: Unknown.

Original source

Catalog source: SkillHub Club.

Repository owner: Automattic.

This is still a mirrored public skill entry. Review the repository before installing into production workflows.

What it helps with

  • Install activitypub-federation into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
  • Review https://github.com/Automattic/wordpress-activitypub before adding activitypub-federation to shared team environments
  • Use activitypub-federation for integration workflows

Works across

Claude CodeCodex CLIGemini CLIOpenCode

Favorites: 0.

Sub-skills: 0.

Aggregator: No.

Original source / Raw SKILL.md

---
name: activitypub-federation
description: ActivityPub protocol specification and federation concepts. Use when working with ActivityPub activities, understanding federation mechanics, implementing protocol features, or debugging federation issues.
---

# ActivityPub Federation Protocol

This skill provides understanding of the ActivityPub protocol specification and how federation works.

**For supported features and compatibility:** See [FEDERATION.md](../../../FEDERATION.md) for the complete list of implemented FEPs, supported standards, and federation compatibility details.

**For implementation details:** See [PHP Conventions](../activitypub-php-conventions/SKILL.md) for transformers, handlers, and PHP code patterns.

## Core Concepts

### Three Building Blocks

1. **Actors** - Users/accounts in the system
   - Each actor has a unique URI
   - Required: `inbox`, `outbox`
   - Optional: `followers`, `following`, `liked`

2. **Activities** - Actions taken by actors
   - Create, Update, Delete, Follow, Like, Announce, Undo
   - Wrap objects to describe how they're shared

3. **Objects** - Content being acted upon
   - Notes, Articles, Images, Videos, etc.
   - Can be embedded or referenced by URI

### Actor Structure

```json
{
  "@context": "https://www.w3.org/ns/activitystreams",
  "type": "Person",
  "id": "https://example.com/@alice",
  "inbox": "https://example.com/@alice/inbox",
  "outbox": "https://example.com/@alice/outbox",
  "followers": "https://example.com/@alice/followers",
  "following": "https://example.com/@alice/following",
  "preferredUsername": "alice",
  "name": "Alice Example",
  "summary": "Bio text here"
}
```

## Collections

### Standard Collections

**Inbox** - Receives incoming activities
- De-duplicate by activity ID
- Filter based on permissions
- Process activities for side effects

**Outbox** - Publishes actor's activities
- Public record of what actor has posted
- Filtered based on viewer permissions
- Used for profile activity displays

**Followers** - Actors following this actor
- Updated when Follow activities are Accepted
- Used for delivery targeting

**Following** - Actors this actor follows
- Tracks subscriptions
- Used for timeline building

### Public Addressing

Special collection: `https://www.w3.org/ns/activitystreams#Public`

- Makes content publicly accessible
- **Do not deliver to this URI** - it's a marker, not a real inbox
- Used in `to`, `cc`, `bto`, `bcc` fields for visibility

## Activity Types

### Create
Wraps newly published content:
```json
{
  "type": "Create",
  "actor": "https://example.com/@alice",
  "object": {
    "type": "Note",
    "content": "Hello, Fediverse!"
  }
}
```

### Follow
Initiates subscription:
```json
{
  "type": "Follow",
  "actor": "https://example.com/@alice",
  "object": "https://other.example/@bob"
}
```
- Recipient should respond with Accept or Reject
- Only add to followers upon Accept

### Like
Indicates appreciation:
```json
{
  "type": "Like",
  "actor": "https://example.com/@alice",
  "object": "https://other.example/@bob/post/123"
}
```

### Announce
Reshares/boosts content:
```json
{
  "type": "Announce",
  "actor": "https://example.com/@alice",
  "object": "https://other.example/@bob/post/123"
}
```

### Update
Modifies existing content:
- Supplied properties replace existing
- `null` values remove fields
- Must include original object ID

### Delete
Removes content:
- May replace with Tombstone for referential integrity
- Should cascade to related activities

### Undo
Reverses previous activities:
```json
{
  "type": "Undo",
  "actor": "https://example.com/@alice",
  "object": {
    "type": "Follow",
    "id": "https://example.com/@alice/follow/123"
  }
}
```

## Server-to-Server Federation

### Activity Delivery Process

1. **Resolve Recipients**
   - Check `to`, `bto`, `cc`, `bcc`, `audience` fields
   - Dereference collections to find individual actors
   - De-duplicate recipient list
   - Exclude activity's own actor

2. **Discover Inboxes**
   - Fetch actor profiles
   - Extract `inbox` property
   - Use `sharedInbox` if available for efficiency

3. **Deliver via HTTP POST**
   - Content-Type: `application/ld+json; profile="https://www.w3.org/ns/activitystreams"`
   - Include HTTP Signatures for authentication
   - Handle delivery failures gracefully

### Inbox Forwarding

**Ghost Replies Problem:** When Alice replies to Bob's post that Carol follows, Carol might not see the reply if she doesn't follow Alice.

**Solution:** Inbox forwarding
- When receiving activity addressing a local collection
- If activity references local objects
- Forward to collection members
- Ensures conversation participants see replies

### Shared Inbox Optimization

For public posts with many recipients on same server:
- Use `sharedInbox` endpoint instead of individual inboxes
- Reduces number of HTTP requests
- Server distributes internally

## Addressing and Visibility

### To/CC Fields

- `to` - Primary recipients (public in UI)
- `cc` - Secondary recipients (copied/mentioned)
- `bto` - Blind primary (hidden in delivery)
- `bcc` - Blind secondary (hidden in delivery)

**Important:** Remove `bto` and `bcc` before delivery to preserve privacy

### Visibility Patterns

**Public Post:**
```json
{
  "to": ["https://www.w3.org/ns/activitystreams#Public"],
  "cc": ["https://example.com/@alice/followers"]
}
```

**Followers-Only:**
```json
{
  "to": ["https://example.com/@alice/followers"]
}
```

**Direct Message:**
```json
{
  "to": ["https://other.example/@bob"],
  "cc": []
}
```

## Content Verification

### Security Considerations

1. **Verify Origins**
   - Don't trust claimed sources without verification
   - Check HTTP Signatures
   - Validate actor owns referenced objects

2. **Prevent Spoofing**
   - Mallory could claim Alice posted something
   - Always verify before processing side effects

3. **Rate Limiting**
   - Limit recursive dereferencing
   - Protect against denial-of-service
   - Implement spam filtering

4. **Content Sanitization**
   - Clean HTML before browser rendering
   - Validate media types
   - Check for malicious payloads

## Protocol Extensions

### Supported Standards

See [FEDERATION.md](../../../FEDERATION.md) for the complete list of implemented standards and FEPs, including:
- WebFinger - Actor discovery.
- HTTP Signatures - Request authentication.
- NodeInfo - Server metadata.
- Various FEPs (Fediverse Enhancement Proposals).

### FEPs (Fediverse Enhancement Proposals)

FEPs extend ActivityPub with additional features. Common FEP categories include:
- Long-form text support.
- Quote posts.
- Activity intents.
- Follower synchronization.
- Actor metadata extensions.

**For supported FEPs in this plugin:** See [FEDERATION.md](../../../FEDERATION.md) for the authoritative list of implemented FEPs.

## Implementation Notes

### WordPress Plugin Specifics

This plugin implements:
- **Actor Types**: User, Blog, Application
- **Transformers**: Convert WordPress content to ActivityPub objects
- **Handlers**: Process incoming activities

For implementation details, see:
- [PHP Conventions](../activitypub-php-conventions/SKILL.md) for code structure
- [Integration Guide](../activitypub-integrations/SKILL.md) for extending

### Testing Federation

```bash
# Test actor endpoint
curl -H "Accept: application/activity+json" \
  https://site.com/@username

# Test WebFinger
curl https://site.com/.well-known/webfinger?resource=acct:[email protected]

# Test NodeInfo
curl https://site.com/.well-known/nodeinfo
```

## Common Issues

### Activities Not Received
- Check inbox URL is accessible
- Verify HTTP signature validation
- Ensure content-type headers correct
- Check for firewall/security blocks

### Replies Not Federated
- Verify inbox forwarding enabled
- Check addressing includes relevant actors
- Ensure `inReplyTo` properly set

### Follower Sync Issues
- Check Accept activities sent for Follow
- Verify followers collection updates
- Ensure shared inbox used when available

## Resources

- [ActivityPub Spec](https://www.w3.org/TR/activitypub/)
- [ActivityStreams Vocabulary](https://www.w3.org/TR/activitystreams-vocabulary/)
- [Project FEDERATION.md](../../../FEDERATION.md)
- [FEPs Repository](https://codeberg.org/fediverse/fep)

---

## Referenced Files

> The following files are referenced in this skill and included for context.

### ../../../FEDERATION.md

```markdown
# Federation in WordPress

The WordPress plugin largely follows ActivityPub's server-to-server specification, but makes use of some non-standard extensions, some of which are required to interact with the plugin. Most of these extensions are for the purpose of compatibility with other, sometimes very restrictive networks, such as Mastodon.

## Supported federation protocols and standards

- [ActivityPub](https://www.w3.org/TR/activitypub/) (Server-to-Server)
- [WebFinger](https://www.w3.org/community/reports/socialcg/CG-FINAL-apwf-20240608/)
- [HTTP Signatures](https://swicg.github.io/activitypub-http-signature/)
- [NodeInfo](https://nodeinfo.diaspora.software/)
- [Interaction Policy](https://docs.gotosocial.org/en/latest/federation/interaction_policy/)

## Supported FEPs

- [FEP-f1d5: NodeInfo in Fediverse Software](https://codeberg.org/fediverse/fep/src/branch/main/fep/f1d5/fep-f1d5.md)
- [FEP-0151: NodeInfo in Fediverse Software (2025 edition)](https://codeberg.org/fediverse/fep/src/branch/main/fep/0151/fep-0151.md)
- [FEP-67ff: FEDERATION.md](https://codeberg.org/fediverse/fep/src/branch/main/fep/67ff/fep-67ff.md)
- [FEP-5feb: Search indexing consent for actors](https://codeberg.org/fediverse/fep/src/branch/main/fep/5feb/fep-5feb.md)
- [FEP-2677: Identifying the Application Actor](https://codeberg.org/fediverse/fep/src/branch/main/fep/2677/fep-2677.md)
- [FEP-2c59: Discovery of a Webfinger address from an ActivityPub actor](https://codeberg.org/fediverse/fep/src/branch/main/fep/2c59/fep-2c59.md)
- [FEP-fb2a: Actor metadata](https://codeberg.org/fediverse/fep/src/branch/main/fep/fb2a/fep-fb2a.md)
- [FEP-b2b8: Long-form Text](https://codeberg.org/fediverse/fep/src/branch/main/fep/b2b8/fep-b2b8.md)
- [FEP-7888: Demystifying the context property](https://codeberg.org/fediverse/fep/src/branch/main/fep/7888/fep-7888.md)
- [FEP-844e: Capability discovery](https://codeberg.org/fediverse/fep/src/branch/main/fep/844e/fep-844e.md)
- [FEP-044f: Consent-respecting quote posts](https://codeberg.org/fediverse/fep/src/branch/main/fep/044f/fep-044f.md)
- [FEP-3b86: Activity Intents](https://codeberg.org/fediverse/fep/src/branch/main/fep/3b86/fep-3b86.md)
- [FEP-8fcf: Followers collection synchronization across servers](https://codeberg.org/fediverse/fep/src/branch/main/fep/8fcf/fep-8fcf.md)

Partially supported FEPs

- [FEP-1b12: Group federation](https://codeberg.org/fediverse/fep/src/branch/main/fep/1b12/fep-1b12.md)

## ActivityPub

### HTTP Signatures

In order to authenticate activities, Mastodon relies on HTTP Signatures, signing every `POST` and `GET` request to other ActivityPub implementations on behalf of the user authoring an activity (for `POST` requests) or an actor representing the Mastodon server itself (for most `GET` requests).

Mastodon requires all `POST` requests to be signed, and MAY require `GET` requests to be signed, depending on the configuration of the Mastodon server.

More information on HTTP Signatures, as well as examples, can be found here: <https://docs.joinmastodon.org/spec/security/#http>

## Additional documentation

- Plugin Documentation: [docs/readme.md](docs/readme.md)
- Changelog: <https://github.com/Automattic/wordpress-activitypub/blob/trunk/CHANGELOG.md>

```

### ../activitypub-php-conventions/SKILL.md

```markdown
---
name: activitypub-php-conventions
description: PHP coding standards and WordPress patterns for ActivityPub plugin. Use when writing PHP code, creating classes, implementing WordPress hooks, or structuring plugin files.
---

# ActivityPub PHP Conventions

Plugin-specific conventions and architectural patterns for the ActivityPub plugin.

## Quick Reference

### File Naming
```
class-{name}.php         # Regular classes.
trait-{name}.php         # Traits.
interface-{name}.php     # Interfaces.
```

### Namespace Pattern
```php
namespace Activitypub;
namespace Activitypub\Transformer;
namespace Activitypub\Collection;
namespace Activitypub\Handler;
namespace Activitypub\Activity;
namespace Activitypub\Rest;
```

### Text Domain
Always use `'activitypub'` for translations:
```php
\__( 'Text', 'activitypub' );
\_e( 'Text', 'activitypub' );
```

### WordPress Global Functions
When in a namespace, always escape WordPress functions with backslash: `\get_option()`, `\add_action()`, etc.

## Comprehensive Standards

See [PHP Coding Standards](../../../docs/php-coding-standards.md) for complete WordPress coding standards.

See [PHP Class Structure](../../../docs/php-class-structure.md) for detailed directory organization.

## Directory Structure

```
includes/
├── class-*.php              # Core classes.
├── activity/                # Activity type classes.
├── collection/              # Collection classes.
├── handler/                 # Activity handlers.
├── rest/                    # REST API endpoints.
├── transformer/             # Content transformers.
└── wp-admin/                # Admin functionality.

integration/                 # Third-party integrations (root level).
```

## ActivityPub Architectural Patterns

### Transformers
Convert WordPress content into ActivityPub objects.

**When to use:** Converting posts, comments, users, or custom content types into ActivityPub format.

**Base class:** `includes/transformer/class-base.php`

**Pattern:**
```php
namespace Activitypub\Transformer;

class Custom extends Base {
    /**
     * Transform object to ActivityPub format.
     *
     * @return array The ActivityPub representation.
     */
    public function transform() {
        $object = parent::transform();
        // Custom transformation logic.
        return $object;
    }
}
```

**Examples:**
- `includes/transformer/class-post.php` - Post transformation.
- `includes/transformer/class-comment.php` - Comment transformation.
- `includes/transformer/class-event.php` - Event-specific transformation.

### Handlers
Process incoming ActivityPub activities from remote servers.

**When to use:** Processing incoming Follow, Like, Create, Delete, Update, etc. activities.

**Pattern:** Each handler processes one activity type from the inbox.

**Examples:**
- `includes/handler/class-follow.php` - Process Follow activities.
- `includes/handler/class-create.php` - Process Create activities.
- `includes/handler/class-delete.php` - Process Delete activities.
- `includes/handler/class-like.php` - Process Like activities.

### Collections
Implement ActivityPub collections (Followers, Following, etc.).

**When to use:** Exposing lists of actors, activities, or objects via ActivityPub.

**Examples:**
- `includes/collection/class-followers.php` - Followers collection.
- `includes/collection/class-following.php` - Following collection.

### REST API Controllers
Expose ActivityPub endpoints.

**Namespace:** `ACTIVITYPUB_REST_NAMESPACE`

**Examples:**
- `includes/rest/class-actors-controller.php` - Actor endpoint.
- `includes/rest/class-inbox-controller.php` - Inbox endpoint.
- `includes/rest/class-outbox-controller.php` - Outbox endpoint.
- `includes/rest/class-followers-controller.php` - Followers collection endpoint.

## Plugin-Specific Helper Functions

```php
// Get remote actor metadata.
$metadata = get_remote_metadata_by_actor( $actor_url );

// Convert ActivityPub object to URI string.
$uri = object_to_uri( $object );

// Enrich content with callbacks.
$content = enrich_content_data( $content, $pattern, $callback );

// Resolve WebFinger handle to actor URL.
$resource = Webfinger::resolve( $handle );

// Get user's ActivityPub actor URL.
$actor_url = get_author_posts_url( $user_id );

// Check if a post type is enabled for ActivityPub.
$enabled = \is_post_type_enabled( $post_type );
```

## Real Codebase Examples

**Core Classes:**
- `includes/class-activitypub.php` - Main plugin initialization.
- `includes/class-dispatcher.php` - Activity dispatching to followers.
- `includes/class-scheduler.php` - WP-Cron integration for async tasks.
- `includes/class-signature.php` - HTTP Signatures for federation.

**Activity Types:**
- `includes/activity/class-activity.php` - Base activity class.
- `includes/activity/class-follow.php` - Follow activity.
- `includes/activity/class-undo.php` - Undo activity.

**Integrations (see [Integration Patterns](../activitypub-integrations/SKILL.md)):**
- `integration/class-woocommerce.php` - WooCommerce integration.
- `integration/class-buddypress.php` - BuddyPress integration.
- `integration/class-jetpack.php` - Jetpack integration.

## Common Initialization Patterns

### Static Initialization
```php
class Feature {
    /**
     * Initialize the class.
     */
    public static function init() {
        \add_action( 'init', array( self::class, 'register' ) );
        \add_filter( 'activitypub_activity_object', array( self::class, 'filter' ) );
    }
}
```

### Singleton Pattern
```php
class Manager {
    private static $instance = null;

    public static function get_instance() {
        if ( null === self::$instance ) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    private function __construct() {
        $this->init();
    }
}
```

## Custom Hook Patterns

**Actions:**
```php
\do_action( 'activitypub_before_send_activity', $activity );
\do_action( 'activitypub_after_send_activity', $activity, $response );
\do_action( 'activitypub_inbox_received', $activity );
```

**Filters:**
```php
$activity = \apply_filters( 'activitypub_activity_object', $activity, $post );
$content = \apply_filters( 'activitypub_the_content', $content, $post );
$actor = \apply_filters( 'activitypub_actor_data', $actor, $user_id );
```

```

### ../activitypub-integrations/SKILL.md

```markdown
---
name: activitypub-integrations
description: Third-party WordPress plugin integration patterns. Use when adding new integrations, debugging compatibility with other plugins, or working with existing integrations.
---

# ActivityPub Integrations

This skill provides guidance on integrating the ActivityPub plugin with other WordPress plugins.

## Quick Reference

### Integration Location
All integrations live in the `integration/` directory.

**File naming:** `class-{plugin-name}.php` (following [PHP conventions](../activitypub-php-conventions/SKILL.md))

### Available Integrations
- BuddyPress
- bbPress
- WooCommerce
- Jetpack
- The Events Calendar
- WP User Avatars
- And 13+ more

For complete directory structure and naming conventions, see [PHP Class Structure](../../../docs/php-class-structure.md).

## Creating New Integration

### Basic Integration Class

```php
<?php
namespace Activitypub\Integration;

class Plugin_Name {
    public static function init() {
        \add_filter( 'activitypub_transformer', array( self::class, 'custom_transformer' ), 10, 2 );
        \add_filter( 'activitypub_post_types', array( self::class, 'add_post_types' ) );
    }

    public static function custom_transformer( $transformer, $object ) {
        // Return custom transformer if needed.
        return $transformer;
    }

    public static function add_post_types( $post_types ) {
        // Add plugin's post types.
        $post_types[] = 'plugin_post_type';
        return $post_types;
    }
}
```

## Integration Patterns

### Adding Post Type Support

```php
public static function add_post_types( $post_types ) {
    $post_types[] = 'event';
    $post_types[] = 'product';
    return $post_types;
}
```

### Custom Transformers

```php
public static function transformer( $transformer, $object ) {
    if ( 'custom_type' === get_post_type( $object ) ) {
        require_once __DIR__ . '/transformer/class-custom.php';
        return new Transformer\Custom( $object );
    }
    return $transformer;
}
```

### Modifying Activities

```php
\add_filter( 'activitypub_activity_object', function( $object, $post ) {
    if ( 'product' === get_post_type( $post ) ) {
        $object['type']  = 'Product';
        $object['price'] = get_post_meta( $post->ID, 'price', true );
    }
    return $object;
}, 10, 2 );
```

## Testing Integrations

### Verify Integration Loading

```php
// Check if integration is active.
if ( class_exists( '\Activitypub\Integration\Plugin_Name' ) ) {
    // Integration loaded.
}
```

### Test Compatibility

1. Install target plugin
2. Activate ActivityPub
3. Check for conflicts
4. Verify custom post types work
5. Test federation of plugin content

## Common Integration Issues

### Plugin Detection
```php
// Multiple detection methods.
if ( defined( 'PLUGIN_VERSION' ) ) { }
if ( function_exists( 'plugin_function' ) ) { }
if ( class_exists( 'Plugin_Class' ) ) { }
```

### Hook Priority
```php
// Use appropriate priority.
add_filter( 'hook', 'callback', 20 ); // After plugin's filter.
```

### Namespace Conflicts
```php
// Use fully qualified names.
$object = new \Plugin\Namespace\Class();
```

## Existing Integrations

### BuddyPress
- Adds BuddyPress activity support
- Custom member transformers
- Group activity federation

### WooCommerce
- Product post type support
- Order activity notifications
- Customer review federation

### bbPress
- Forum topic federation
- Reply activities
- User forum profiles

## Best Practices

1. **Always check if plugin is active** before adding hooks
2. **Use late priority** for filters to override plugin defaults
3. **Test with multiple plugin versions**
4. **Document compatibility requirements**
5. **Handle plugin deactivation gracefully**

```