jira-project-management

Jira Project Management Skill

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "jira-project-management" with this command: npx skills add neversight/skills_feed/neversight-skills-feed-jira-project-management

Jira Project Management Skill

Purpose

Comprehensive project administration including CRUD operations, components, versions, roles, permissions, and configuration.

When to Use

  • Creating/updating/deleting/archiving projects

  • Managing project components (modules, teams)

  • Managing versions/releases

  • Configuring project roles and permissions

  • Setting project properties and metadata

  • Validating project keys and names

Prerequisites

  • Authenticated JiraClient (see jira-auth skill)

  • Jira admin or project admin permissions

  • Project key format: 2-10 uppercase letters

Implementation Pattern

Step 1: Define Types

interface Project { id: string; key: string; name: string; self: string; projectTypeKey: 'software' | 'service_desk' | 'business'; simplified: boolean; style: 'classic' | 'next-gen'; isPrivate: boolean; lead: { accountId: string; displayName: string; }; description?: string; url?: string; avatarUrls: Record<string, string>; projectCategory?: { id: string; name: string; }; }

interface Component { id: string; name: string; description?: string; lead?: { accountId: string; displayName: string }; assigneeType: 'PROJECT_DEFAULT' | 'COMPONENT_LEAD' | 'PROJECT_LEAD' | 'UNASSIGNED'; project: string; projectId: number; }

interface Version { id: string; name: string; description?: string; archived: boolean; released: boolean; startDate?: string; releaseDate?: string; projectId: number; overdue?: boolean; }

interface ProjectRole { id: number; name: string; description: string; actors: Array<{ id: number; displayName: string; type: 'atlassian-user-role-actor' | 'atlassian-group-role-actor'; actorUser?: { accountId: string }; actorGroup?: { name: string; displayName: string }; }>; }

Step 2: Project CRUD Operations

// Create Project interface CreateProjectInput { key: string; // 2-10 uppercase letters name: string; projectTypeKey: 'software' | 'service_desk' | 'business'; leadAccountId: string; description?: string; assigneeType?: 'PROJECT_LEAD' | 'UNASSIGNED'; categoryId?: number; }

async function createProject( client: JiraClient, input: CreateProjectInput ): Promise<Project> { return client.request<Project>('/project', { method: 'POST', body: JSON.stringify({ key: input.key, name: input.name, projectTypeKey: input.projectTypeKey, leadAccountId: input.leadAccountId, description: input.description, assigneeType: input.assigneeType || 'UNASSIGNED', categoryId: input.categoryId, }), }); }

// Update Project async function updateProject( client: JiraClient, projectKeyOrId: string, updates: Partial<{ key: string; name: string; description: string; leadAccountId: string; assigneeType: string; categoryId: number; }> ): Promise<Project> { return client.request<Project>(/project/${projectKeyOrId}, { method: 'PUT', body: JSON.stringify(updates), }); }

// Delete Project (moves to trash, recoverable for 60 days) async function deleteProject( client: JiraClient, projectKeyOrId: string, enableUndo: boolean = true ): Promise<void> { await client.request(/project/${projectKeyOrId}?enableUndo=${enableUndo}, { method: 'DELETE', }); }

// Archive Project async function archiveProject( client: JiraClient, projectKeyOrId: string ): Promise<void> { await client.request(/project/${projectKeyOrId}/archive, { method: 'POST', }); }

// Restore Project async function restoreProject( client: JiraClient, projectKeyOrId: string ): Promise<Project> { return client.request<Project>(/project/${projectKeyOrId}/restore, { method: 'POST', }); }

Step 3: List and Search Projects

interface ProjectSearchOptions { startAt?: number; maxResults?: number; orderBy?: 'category' | '-category' | 'key' | '-key' | 'name' | '-name' | 'owner' | '-owner'; query?: string; // Search in name/key typeKey?: string; // software, service_desk, business categoryId?: number; expand?: ('description' | 'lead' | 'issueTypes' | 'url' | 'projectKeys' | 'permissions' | 'insight')[]; }

async function searchProjects( client: JiraClient, options: ProjectSearchOptions = {} ): Promise<{ values: Project[]; total: number; isLast: boolean }> { const params = new URLSearchParams(); if (options.startAt) params.set('startAt', String(options.startAt)); if (options.maxResults) params.set('maxResults', String(options.maxResults)); if (options.orderBy) params.set('orderBy', options.orderBy); if (options.query) params.set('query', options.query); if (options.typeKey) params.set('typeKey', options.typeKey); if (options.categoryId) params.set('categoryId', String(options.categoryId)); if (options.expand) params.set('expand', options.expand.join(','));

return client.request(/project/search?${params.toString()}); }

// Get recent projects async function getRecentProjects( client: JiraClient, maxResults: number = 20 ): Promise<Project[]> { const params = new URLSearchParams(); params.set('maxResults', String(maxResults)); params.set('expand', 'description,lead'); return client.request(/project/recent?${params.toString()}); }

Step 4: Component Management

// List Components async function getProjectComponents( client: JiraClient, projectKeyOrId: string ): Promise<Component[]> { return client.request(/project/${projectKeyOrId}/components); }

// Create Component interface CreateComponentInput { project: string; // Project key name: string; description?: string; leadAccountId?: string; assigneeType?: 'PROJECT_DEFAULT' | 'COMPONENT_LEAD' | 'PROJECT_LEAD' | 'UNASSIGNED'; }

async function createComponent( client: JiraClient, input: CreateComponentInput ): Promise<Component> { return client.request<Component>('/component', { method: 'POST', body: JSON.stringify({ project: input.project, name: input.name, description: input.description, leadAccountId: input.leadAccountId, assigneeType: input.assigneeType || 'PROJECT_DEFAULT', }), }); }

// Update Component async function updateComponent( client: JiraClient, componentId: string, updates: Partial<{ name: string; description: string; leadAccountId: string; assigneeType: string; }> ): Promise<Component> { return client.request<Component>(/component/${componentId}, { method: 'PUT', body: JSON.stringify(updates), }); }

// Delete Component async function deleteComponent( client: JiraClient, componentId: string, moveIssuesTo?: string // Component ID to move issues to ): Promise<void> { const query = moveIssuesTo ? ?moveIssuesTo=${moveIssuesTo} : ''; await client.request(/component/${componentId}${query}, { method: 'DELETE', }); }

// Get Component Issue Counts async function getComponentIssueCounts( client: JiraClient, componentId: string ): Promise<{ issueCount: number }> { return client.request(/component/${componentId}/relatedIssueCounts); }

Step 5: Version/Release Management

// List Versions async function getProjectVersions( client: JiraClient, projectKeyOrId: string, options: { startAt?: number; maxResults?: number; orderBy?: 'description' | '-description' | 'name' | '-name' | 'releaseDate' | '-releaseDate' | 'sequence' | '-sequence' | 'startDate' | '-startDate'; status?: 'released' | 'unreleased' | 'archived'; expand?: string; } = {} ): Promise<{ values: Version[]; total: number; isLast: boolean }> { const params = new URLSearchParams(); if (options.startAt) params.set('startAt', String(options.startAt)); if (options.maxResults) params.set('maxResults', String(options.maxResults)); if (options.orderBy) params.set('orderBy', options.orderBy); if (options.status) params.set('status', options.status); if (options.expand) params.set('expand', options.expand);

return client.request(/project/${projectKeyOrId}/version?${params.toString()}); }

// Create Version interface CreateVersionInput { projectId: number; name: string; description?: string; startDate?: string; // YYYY-MM-DD releaseDate?: string; // YYYY-MM-DD released?: boolean; archived?: boolean; }

async function createVersion( client: JiraClient, input: CreateVersionInput ): Promise<Version> { return client.request<Version>('/version', { method: 'POST', body: JSON.stringify(input), }); }

// Update Version async function updateVersion( client: JiraClient, versionId: string, updates: Partial<{ name: string; description: string; startDate: string; releaseDate: string; released: boolean; archived: boolean; moveUnfixedIssuesTo: string; // Version ID when releasing }> ): Promise<Version> { return client.request<Version>(/version/${versionId}, { method: 'PUT', body: JSON.stringify(updates), }); }

// Release Version (mark as released) async function releaseVersion( client: JiraClient, versionId: string, moveUnfixedIssuesTo?: string ): Promise<Version> { return updateVersion(client, versionId, { released: true, releaseDate: new Date().toISOString().split('T')[0], moveUnfixedIssuesTo, }); }

// Delete Version async function deleteVersion( client: JiraClient, versionId: string, options: { moveFixedIssuesTo?: string; moveAffectedIssuesTo?: string; } = {} ): Promise<void> { const params = new URLSearchParams(); if (options.moveFixedIssuesTo) params.set('moveFixedIssuesTo', options.moveFixedIssuesTo); if (options.moveAffectedIssuesTo) params.set('moveAffectedIssuesTo', options.moveAffectedIssuesTo);

const query = params.toString() ? ?${params.toString()} : ''; await client.request(/version/${versionId}${query}, { method: 'DELETE', }); }

// Get Version Issue Counts async function getVersionIssueCounts( client: JiraClient, versionId: string ): Promise<{ issuesFixedCount: number; issuesAffectedCount: number; issueCountWithCustomFieldsShowingVersion: number; }> { return client.request(/version/${versionId}/relatedIssueCounts); }

// Get Unresolved Issue Count async function getUnresolvedIssueCount( client: JiraClient, versionId: string ): Promise<{ issuesUnresolvedCount: number; self: string }> { return client.request(/version/${versionId}/unresolvedIssueCount); }

Step 6: Project Roles

// Get Project Roles async function getProjectRoles( client: JiraClient, projectKeyOrId: string ): Promise<Record<string, string>> { // Returns map of role name -> role URL return client.request(/project/${projectKeyOrId}/role); }

// Get Role Details async function getProjectRole( client: JiraClient, projectKeyOrId: string, roleId: number ): Promise<ProjectRole> { return client.request(/project/${projectKeyOrId}/role/${roleId}); }

// Add User to Role async function addUserToRole( client: JiraClient, projectKeyOrId: string, roleId: number, accountId: string ): Promise<ProjectRole> { return client.request(/project/${projectKeyOrId}/role/${roleId}, { method: 'POST', body: JSON.stringify({ user: [accountId], }), }); }

// Add Group to Role async function addGroupToRole( client: JiraClient, projectKeyOrId: string, roleId: number, groupName: string ): Promise<ProjectRole> { return client.request(/project/${projectKeyOrId}/role/${roleId}, { method: 'POST', body: JSON.stringify({ group: [groupName], }), }); }

// Remove Actor from Role async function removeActorFromRole( client: JiraClient, projectKeyOrId: string, roleId: number, actorType: 'user' | 'group', actorValue: string // accountId or groupName ): Promise<void> { const param = actorType === 'user' ? 'user' : 'group'; await client.request( /project/${projectKeyOrId}/role/${roleId}?${param}=${encodeURIComponent(actorValue)}, { method: 'DELETE' } ); }

Step 7: Project Properties

// List Project Properties async function getProjectProperties( client: JiraClient, projectKeyOrId: string ): Promise<{ keys: Array<{ key: string; self: string }> }> { return client.request(/project/${projectKeyOrId}/properties); }

// Get Property async function getProjectProperty( client: JiraClient, projectKeyOrId: string, propertyKey: string ): Promise<{ key: string; value: any }> { return client.request(/project/${projectKeyOrId}/properties/${propertyKey}); }

// Set Property async function setProjectProperty( client: JiraClient, projectKeyOrId: string, propertyKey: string, value: any ): Promise<void> { await client.request(/project/${projectKeyOrId}/properties/${propertyKey}, { method: 'PUT', body: JSON.stringify(value), }); }

// Delete Property async function deleteProjectProperty( client: JiraClient, projectKeyOrId: string, propertyKey: string ): Promise<void> { await client.request(/project/${projectKeyOrId}/properties/${propertyKey}, { method: 'DELETE', }); }

Step 8: Project Validation

// Validate Project Key async function validateProjectKey( client: JiraClient, key: string ): Promise<{ errorMessages: string[]; errors: Record<string, string> }> { return client.request(/projectvalidate/key?key=${encodeURIComponent(key)}); }

// Get Valid Project Key Suggestion async function getValidProjectKey( client: JiraClient, key: string ): Promise<string> { return client.request(/projectvalidate/validProjectKey?key=${encodeURIComponent(key)}); }

// Get Valid Project Name async function getValidProjectName( client: JiraClient, name: string ): Promise<string> { return client.request(/projectvalidate/validProjectName?name=${encodeURIComponent(name)}); }

// Get Project Types async function getProjectTypes( client: JiraClient ): Promise<Array<{ key: string; formattedKey: string; descriptionI18nKey: string; icon: string; color: string; }>> { return client.request('/project/type'); }

Step 9: High-Level Helpers

// Full project setup with components and version async function setupProject( client: JiraClient, config: { key: string; name: string; leadAccountId: string; description?: string; components?: string[]; initialVersion?: string; } ): Promise<{ project: Project; components: Component[]; version?: Version; }> { // Create project const project = await createProject(client, { key: config.key, name: config.name, projectTypeKey: 'software', leadAccountId: config.leadAccountId, description: config.description, });

// Create components const components: Component[] = []; for (const compName of config.components || []) { const comp = await createComponent(client, { project: project.key, name: compName, }); components.push(comp); }

// Create initial version let version: Version | undefined; if (config.initialVersion) { version = await createVersion(client, { projectId: parseInt(project.id), name: config.initialVersion, }); }

return { project, components, version }; }

// Clone project structure (components + unreleased versions) async function cloneProjectStructure( client: JiraClient, sourceProjectKey: string, targetProjectKey: string ): Promise<{ componentsCloned: number; versionsCloned: number; }> { // Get source components const sourceComponents = await getProjectComponents(client, sourceProjectKey);

// Get source versions (unreleased only) const sourceVersions = await getProjectVersions(client, sourceProjectKey, { status: 'unreleased', });

// Get target project const targetProject = await client.request<Project>(/project/${targetProjectKey});

// Clone components for (const comp of sourceComponents) { await createComponent(client, { project: targetProjectKey, name: comp.name, description: comp.description, }); }

// Clone versions for (const ver of sourceVersions.values) { await createVersion(client, { projectId: parseInt(targetProject.id), name: ver.name, description: ver.description, startDate: ver.startDate, releaseDate: ver.releaseDate, }); }

return { componentsCloned: sourceComponents.length, versionsCloned: sourceVersions.values.length, }; }

curl Examples

Create Project

curl -X POST "$JIRA_BASE_URL/rest/api/3/project"
-H "Authorization: Basic $(echo -n 'email:token' | base64)"
-H "Content-Type: application/json"
-d '{ "key": "NEWPROJ", "name": "New Project", "projectTypeKey": "software", "leadAccountId": "5b10a2844c20165700ede21g", "description": "Project description" }'

Update Project

curl -X PUT "$JIRA_BASE_URL/rest/api/3/project/SCRUM"
-H "Authorization: Basic $(echo -n 'email:token' | base64)"
-H "Content-Type: application/json"
-d '{ "name": "Updated Project Name", "description": "Updated description" }'

Delete Project

curl -X DELETE "$JIRA_BASE_URL/rest/api/3/project/SCRUM?enableUndo=true"
-H "Authorization: Basic $(echo -n 'email:token' | base64)"

Search Projects

curl -X GET "$JIRA_BASE_URL/rest/api/3/project/search?query=scrum&expand=description,lead"
-H "Authorization: Basic $(echo -n 'email:token' | base64)"
-H "Accept: application/json"

Create Component

curl -X POST "$JIRA_BASE_URL/rest/api/3/component"
-H "Authorization: Basic $(echo -n 'email:token' | base64)"
-H "Content-Type: application/json"
-d '{ "project": "SCRUM", "name": "Backend", "description": "Backend services" }'

Create Version

curl -X POST "$JIRA_BASE_URL/rest/api/3/version"
-H "Authorization: Basic $(echo -n 'email:token' | base64)"
-H "Content-Type: application/json"
-d '{ "projectId": 10000, "name": "v1.0.0", "description": "First release", "releaseDate": "2025-01-15" }'

Release Version

curl -X PUT "$JIRA_BASE_URL/rest/api/3/version/10001"
-H "Authorization: Basic $(echo -n 'email:token' | base64)"
-H "Content-Type: application/json"
-d '{ "released": true, "releaseDate": "2025-12-10" }'

Get Project Roles

curl -X GET "$JIRA_BASE_URL/rest/api/3/project/SCRUM/role"
-H "Authorization: Basic $(echo -n 'email:token' | base64)"
-H "Accept: application/json"

Add User to Role

curl -X POST "$JIRA_BASE_URL/rest/api/3/project/SCRUM/role/10002"
-H "Authorization: Basic $(echo -n 'email:token' | base64)"
-H "Content-Type: application/json"
-d '{ "user": ["5b10a2844c20165700ede21g"] }'

Validate Project Key

curl -X GET "$JIRA_BASE_URL/rest/api/3/projectvalidate/key?key=NEWPROJ"
-H "Authorization: Basic $(echo -n 'email:token' | base64)"
-H "Accept: application/json"

Set Project Property

curl -X PUT "$JIRA_BASE_URL/rest/api/3/project/SCRUM/properties/custom-config"
-H "Authorization: Basic $(echo -n 'email:token' | base64)"
-H "Content-Type: application/json"
-d '{"setting1": "value1", "setting2": true}'

API Endpoints Summary

Operation Method Path

Create project POST /project

Get project GET /project/{projectIdOrKey}

Update project PUT /project/{projectIdOrKey}

Delete project DELETE /project/{projectIdOrKey}

Archive project POST /project/{projectIdOrKey}/archive

Restore project POST /project/{projectIdOrKey}/restore

Search projects GET /project/search

Recent projects GET /project/recent

List components GET /project/{projectIdOrKey}/components

Create component POST /component

Update component PUT /component/{id}

Delete component DELETE /component/{id}

List versions GET /project/{projectIdOrKey}/version

Create version POST /version

Update version PUT /version/{id}

Delete version DELETE /version/{id}

Get roles GET /project/{projectIdOrKey}/role

Get role GET /project/{projectIdOrKey}/role/{roleId}

Add to role POST /project/{projectIdOrKey}/role/{roleId}

Remove from role DELETE /project/{projectIdOrKey}/role/{roleId}

List properties GET /project/{projectIdOrKey}/properties

Get property GET /project/{projectIdOrKey}/properties/{key}

Set property PUT /project/{projectIdOrKey}/properties/{key}

Delete property DELETE /project/{projectIdOrKey}/properties/{key}

Validate key GET /projectvalidate/key

Valid key GET /projectvalidate/validProjectKey

Project types GET /project/type

Common Patterns

Project Key Rules

  • 2-10 uppercase letters only

  • Must be unique across instance

  • Cannot be reused for 60 days after deletion

Permission Requirements

Operation Required Permission

Create project Jira admin

Update project Project admin

Delete project Jira admin

Manage components Project admin

Manage versions Project admin

Manage roles Project admin

Project Types

Type Use Case

software

Scrum/Kanban dev projects

service_desk

Customer support projects

business

Simple task tracking

Common Mistakes

  • Using lowercase in project keys

  • Forgetting to get projectId (numeric) for version creation

  • Not handling 404 for deleted/archived projects

  • Assuming role IDs are consistent (query first)

  • Not using enableUndo=true for safe deletion

References

  • Projects API

  • Project Components

  • Project Versions

  • Project Roles

  • Project Properties

Version History

  • 2025-12-10: Created comprehensive project management skill

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

react-best-practices

No summary provided by upstream source.

Repository SourceNeeds Review
General

ui-designer

No summary provided by upstream source.

Repository SourceNeeds Review
General

ai-image-generation

No summary provided by upstream source.

Repository SourceNeeds Review
General

frontend-ui-ux-engineer

No summary provided by upstream source.

Repository SourceNeeds Review