Install
$ agentstack add skill-impertio-studio-nextcloud-claude-skill-package-nextcloud-impl-collaboration ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
nextcloud-impl-collaboration
Quick Reference
Share Types
| Type | Value | shareWith Parameter | |------|-------|-----------------------| | User | 0 | User ID | | Group | 1 | Group ID | | Public link | 3 | (omit entirely) | | Email | 4 | Email address | | Federated | 6 | user@remote.server | | Circle | 7 | Circle ID | | Talk conversation | 10 | Conversation token |
Permission Bitmask
| Permission | Value | Combine with \| | |-----------|-------|-------------------| | Read | 1 | Always included | | Update | 2 | Edit file content | | Create | 4 | Upload to folder | | Delete | 8 | Remove files | | Share | 16 | Re-share | | All | 31 | 1\|2\|4\|8\|16 |
Share API Base URL
/ocs/v2.php/apps/files_sharing/api/v1/shares
ALWAYS include the OCS-APIRequest: true header on every OCS request.
ALWAYS use API v2 (/ocs/v2.php/) -- v1 returns 100 for success instead of standard HTTP codes.
Notification Interfaces
| Interface | Purpose | |-----------|---------| | OCP\Notification\IManager | Create and dispatch notifications | | OCP\Notification\INotifier | Prepare notifications for display (translation/rendering) | | OCP\Notification\INotification | Single notification object | | OCP\Notification\UnknownNotificationException | Thrown when notifier cannot handle a notification |
Activity Interfaces
| Interface | Purpose | |-----------|---------| | OCP\Activity\IManager | Generate and publish activity events | | OCP\Activity\IEvent | Single activity event object | | OCP\Activity\IProvider | Render activity events for display |
Decision Trees
Which Share Type to Use?
Sharing with a specific Nextcloud user?
YES --> shareType=0, shareWith=userId
NO --> Sharing with a group?
YES --> shareType=1, shareWith=groupId
NO --> Creating a public link?
YES --> shareType=3, do NOT set shareWith
NO --> Sharing via email?
YES --> shareType=4, shareWith=email
NO --> Federated (remote server)?
YES --> shareType=6, shareWith=user@server
NO --> Talk conversation?
YES --> shareType=10, shareWith=conversationToken
Notification vs Activity?
Is this a real-time alert requiring user action?
YES --> Use INotificationManager (appears in notification bell)
NO --> Is this a historical record of something that happened?
YES --> Use IActivityManager (appears in activity stream)
NO --> Both? Use BOTH -- they are independent systems
Essential Patterns
Pattern 1: Create a User Share via OCS
use OCP\Http\Client\IClientService;
$client = $clientService->newClient();
$response = $client->post(
$baseUrl . '/ocs/v2.php/apps/files_sharing/api/v1/shares',
[
'headers' => [
'OCS-APIRequest' => 'true',
'Content-Type' => 'application/x-www-form-urlencoded',
],
'auth' => [$username, $password],
'body' => [
'path' => '/Documents/report.pdf',
'shareType' => 0,
'shareWith' => 'targetuser',
'permissions' => 1 | 2, // Read + Update
],
]
);
Pattern 2: Create a Public Link with Expiry
$response = $client->post(
$baseUrl . '/ocs/v2.php/apps/files_sharing/api/v1/shares',
[
'headers' => ['OCS-APIRequest' => 'true'],
'auth' => [$username, $password],
'body' => [
'path' => '/Documents/report.pdf',
'shareType' => 3,
'password' => 'SecurePass123!',
'expireDate' => '2025-12-31',
'permissions' => 1, // Read-only
],
]
);
// The response contains the share token in ocs.data.token
Pattern 3: Share Attributes (Disable Download)
$body = [
'path' => '/Documents/report.pdf',
'shareType' => 3,
'permissions' => 1,
'attributes' => json_encode([
['scope' => 'permissions', 'key' => 'download', 'value' => false],
]),
];
Pattern 4: Create and Dispatch a Notification
use OCP\Notification\IManager as INotificationManager;
class MyService {
public function __construct(
private INotificationManager $notificationManager,
) {}
public function notifyUser(string $userId, string $itemId, string $itemName): void {
$notification = $this->notificationManager->createNotification();
$notification->setApp('myapp')
->setUser($userId)
->setDateTime(new \DateTime())
->setObject('item', $itemId)
->setSubject('new_item', ['itemName' => $itemName]);
$this->notificationManager->notify($notification);
}
}
NEVER put translated strings in setSubject() -- use a language key. Translation happens in the INotifier::prepare() method.
Pattern 5: INotifier Implementation
namespace OCA\MyApp\Notification;
use OCP\IL10N;
use OCP\IURLGenerator;
use OCP\L10N\IFactory;
use OCP\Notification\INotification;
use OCP\Notification\INotifier;
use OCP\Notification\UnknownNotificationException;
class Notifier implements INotifier {
public function __construct(
private IFactory $l10nFactory,
private IURLGenerator $urlGenerator,
) {}
public function getID(): string {
return 'myapp';
}
public function getName(): string {
return $this->l10nFactory->get('myapp')->t('My App');
}
public function prepare(
INotification $notification,
string $languageCode,
): INotification {
if ($notification->getApp() !== 'myapp') {
throw new UnknownNotificationException();
}
$l = $this->l10nFactory->get('myapp', $languageCode);
$params = $notification->getSubjectParameters();
switch ($notification->getSubject()) {
case 'new_item':
$notification->setRichSubject(
$l->t('New item created: {item}'),
[
'item' => [
'type' => 'highlight',
'id' => $notification->getObjectId(),
'name' => $params['itemName'],
],
]
);
break;
default:
throw new UnknownNotificationException();
}
$notification->setIcon(
$this->urlGenerator->imagePath('myapp', 'app-dark.svg')
);
return $notification;
}
}
ALWAYS throw UnknownNotificationException when getApp() does not match or getSubject() is unrecognized -- this lets the next notifier in the chain handle it.
Pattern 6: Register the Notifier
// lib/AppInfo/Application.php
use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IBootContext;
use OCP\AppFramework\Bootstrap\IBootstrap;
use OCP\AppFramework\Bootstrap\IRegistrationContext;
class Application extends App implements IBootstrap {
public const APP_ID = 'myapp';
public function __construct() {
parent::__construct(self::APP_ID);
}
public function register(IRegistrationContext $context): void {
$context->registerNotifierService(Notifier::class);
}
public function boot(IBootContext $context): void {}
}
Pattern 7: Notification with Actions
// In prepare() method, add actions to the notification:
$acceptAction = $notification->createAction();
$acceptAction->setLabel('accept')
->setLink(
$this->urlGenerator->linkToOCSRoute(
'myapp.api.acceptItem',
['id' => $notification->getObjectId()]
),
'POST'
);
$notification->addAction($acceptAction);
Pattern 8: Mark Notification as Processed
// When the user acts on the item, remove the notification:
$notification = $this->notificationManager->createNotification();
$notification->setApp('myapp')
->setUser($userId)
->setObject('item', $itemId);
$this->notificationManager->markProcessed($notification);
Pattern 9: Publish an Activity Event
use OCP\Activity\IManager as IActivityManager;
class MyService {
public function __construct(
private IActivityManager $activityManager,
) {}
public function logItemCreated(string $userId, string $filename): void {
$event = $this->activityManager->generateEvent();
$event->setApp('myapp')
->setType('myapp_updates')
->setAffectedUser($userId)
->setAuthor($userId)
->setTimestamp(time())
->setSubject('item_created', ['filename' => $filename])
->setObject('file', 42, $filename);
$this->activityManager->publish($event);
}
}
Pattern 10: Push Notification Defer/Flush
// When sending multiple notifications in a batch:
$this->notificationManager->defer();
foreach ($users as $userId) {
$notification = $this->notificationManager->createNotification();
$notification->setApp('myapp')
->setUser($userId)
->setDateTime(new \DateTime())
->setObject('batch', $batchId)
->setSubject('batch_ready', ['batchName' => $name]);
$this->notificationManager->notify($notification);
}
$this->notificationManager->flush();
ALWAYS use defer()/flush() when sending notifications to multiple users in a loop -- this batches push notifications into a single request instead of one per user.
NEVER send individual push notifications inside a loop without defer()/flush() -- this causes N separate push requests and severe performance degradation.
Critical Rules
- ALWAYS use OCS API v2 (
/ocs/v2.php/) for the Share API -- v1 uses non-standard status codes. - ALWAYS include the
OCS-APIRequest: trueheader on Share API requests. - NEVER set
shareWithfor public link shares (type 3) -- it is ignored and causes confusion. - NEVER put translated user-facing strings in
setSubject()-- use language keys and translate inprepare(). - ALWAYS throw
UnknownNotificationExceptioninprepare()for unrecognized apps or subjects. - ALWAYS register your
INotifiervia$context->registerNotifierService()inApplication::register(). - ALWAYS use
defer()/flush()when notifying multiple users in a batch. - NEVER forget to call
markProcessed()when a user acts on a notification -- stale notifications degrade UX. - ALWAYS set both
setAffectedUser()andsetAuthor()on activity events -- affected user sees it in their stream, author is who performed the action.
Reference Links
- [references/methods.md](references/methods.md) -- Share API endpoints, Notification interfaces, Activity interfaces
- [references/examples.md](references/examples.md) -- Share CRUD operations, notification lifecycle, activity events
- [references/anti-patterns.md](references/anti-patterns.md) -- Collaboration mistakes and corrections
Official Sources
- https://docs.nextcloud.com/server/latest/developermanual/diggingdeeper/notifications.html
- https://docs.nextcloud.com/server/latest/developermanual/diggingdeeper/activities.html
- https://docs.nextcloud.com/server/latest/developermanual/clientapis/OCS/ocs-share-api.html
- https://github.com/nextcloud/notifications/blob/master/docs/admin-notifications.md
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: Impertio-Studio
- Source: Impertio-Studio/Nextcloud-Claude-Skill-Package
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.