jira-project-management
Administer Jira projects. Use when creating/archiving projects, managing components, versions, roles, permissions, or project configuration.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Administer Jira projects. Use when creating/archiving projects, managing components, versions, roles, permissions, or project configuration.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Manage Jira Agile boards and sprints. Use when listing boards, creating sprints, or moving issues to/from sprints.
Authenticate with Jira Cloud REST API using API tokens. Use when setting up Jira connections, validating credentials, or handling rate limiting.
Create, read, update, and delete Jira issues. Use when managing Stories, Tasks, Bugs, or Epics - includes field updates and metadata.
Manage Jira projects. Use when listing projects, getting project configuration, retrieving issue types, or managing components and versions.
Orchestrate Jira workflows end-to-end. Use when building stories with approvals, transitioning items through lifecycle states, or syncing task completion with Jira.
Implement SAFe methodology in Jira. Use when creating Epics, Features, Stories with proper hierarchy, acceptance criteria, and parent-child linking.
| name | jira-project-management |
| description | Administer Jira projects. Use when creating/archiving projects, managing components, versions, roles, permissions, or project configuration. |
Comprehensive project administration including CRUD operations, components, versions, roles, permissions, and configuration.
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 };
}>;
}
// 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',
});
}
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()}`);
}
// 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`);
}
// 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`);
}
// 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' }
);
}
// 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',
});
}
// 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');
}
// 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 -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"
}'
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"
}'
curl -X DELETE "$JIRA_BASE_URL/rest/api/3/project/SCRUM?enableUndo=true" \
-H "Authorization: Basic $(echo -n 'email:token' | base64)"
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"
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"
}'
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"
}'
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"
}'
curl -X GET "$JIRA_BASE_URL/rest/api/3/project/SCRUM/role" \
-H "Authorization: Basic $(echo -n 'email:token' | base64)" \
-H "Accept: application/json"
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"]
}'
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"
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}'
| 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 |
| 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 |
| Type | Use Case |
|---|---|
software | Scrum/Kanban dev projects |
service_desk | Customer support projects |
business | Simple task tracking |