Token导航 LogoToken导航

Agent Skill · 研究检索

iblai-profile(伊布莱简介)

iblai-profile 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

iblai-profile 是研究检索类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为接触敏感数据;许可证信息还不明确,第三方扫描有提醒项,按安装量在研究检索类的 73,675 个 Skill 里排第 42,577。

总安装 1,058周安装 45GitHub Stars 14下载 371核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
unknown

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:iblai-profile(伊布莱简介)
来源仓库:https://github.com/iblai/vibe
仓库路径:skills/iblai-profile
安装命令:
npx skills add https://github.com/iblai/vibe --skill iblai-profile
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/iblai/vibe --skill iblai-profile

这个 Skill 是做什么的

研究检索类 Skill 主要解决「找资料、核对事实、把来源整理清楚」的问题,通常会让助手先检索再总结。

iblai-profile 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。适用于个人资料管理、信息归档和场景化查询等研究类任务,支持多宿主环境。

通过 npx skills add 命令从指定 GitHub 仓库安装,需确认权限范围和技能功能边界。使用前建议核实维护状态、是否触发联网或文件操作,避免影响系统安全或数据完整性。适用宿主包括 Codex、Claude、Cursor、Gemini CLI,接入前应确认版本、权限和运行环境要求。

来源仓库内路径:skills/iblai-profile

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/iblai/vibe --skill iblai-profile;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要接触敏感数据,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

iblai-profile 怎么安装?

在终端执行 npx skills add https://github.com/iblai/vibe --skill iblai-profile。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

iblai-profile 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

iblai-profile 需要什么权限?

权限级别是接触敏感数据。该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

iblai-profile 是免费的吗?

公开资料没有标注明确许可证,收费和商用限制都无法确认。正式使用前请到来源仓库核对授权说明。

iblai-profile 用的人多吗?

公开数据是累计安装 1,058 次,近一周安装 45 次,下载 371 次,GitHub 14 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

iblai-profile 安全吗?

第三方扫描有提醒项,说明存在需要人工确认的行为。安装前请打开源码看清它读了什么、联网到哪里。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。

先想清楚的地方

  • 需要接触敏感数据,装到常用环境前要先评估影响面。
  • 许可证没有明确标注,能不能商用、能不能再分发都不确定。
  • 第三方扫描存在提醒项或未通过项,需要人工逐条确认。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理研究检索类任务、又不想每次都手写提示词的人。

不太适合

  • 环境里有大量密钥、凭证,不方便给第三方 Skill 读取的人。
  • 需要明确授权才能用到公司项目里的场景。
  • 需要厂商级技术支持和 SLA 的生产系统。

研究检索类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
find-skills

寻找技能 · Codex、Claude

31,199,81316,486操作浏览器MIT有提醒
self-improving-agent

自我改进 Agent · OpenClaw

16,464,0023,396接触敏感数据MIT-0通过
soultrace

灵魂追踪 · Codex、Claude

7,588,94412需要联网未明确有提醒
self-improving

自我完善 · OpenClaw

6,829,2841,046需要联网MIT-0通过
microsoft-foundry

微软代工厂 · Codex、Claude

6,614,144764调用外部服务未明确有提醒
iblai-profile

伊布莱简介 · 本页

1,05814接触敏感数据未明确有提醒

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

/iblai-profile

Add user profile features -- a compact avatar dropdown for your navbar and a full settings page with tabs for Basic info, Social links, Education, Experience, Resume, and Security.

Profile Page

Do NOT add custom styles, colors, or CSS overrides to ibl.ai SDK components. They ship with their own styling. Keep the components as-is. Do NOT implement dark mode unless the user explicitly asks for it.

When building custom UI around SDK components, use the ibl.ai brand:

  • Primary: #0058cc, Gradient: linear-gradient(135deg, #00b0ef, #0058cc)
  • Button: bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white
  • Font: System sans-serif stack, Style: shadcn/ui new-york variant
  • Follow the component hierarchy: use ibl.ai SDK components (@iblai/iblai-js) first, then shadcn/ui for everything else (npx shadcn@latest add <component>). Do NOT write custom components when an ibl.ai or shadcn equivalent exists. Both share the same Tailwind theme and render in ibl.ai brand colors automatically.
  • Follow BRAND.md for colors, typography, spacing, and component styles.

You MUST run /iblai-ops-test before telling the user the work is ready.

After all work is complete, start a dev server (pnpm dev) so the user can see the result at http://localhost:3000.

iblai.env is NOT a .env.local replacement — it only holds the 3 shorthand variables (DOMAIN, PLATFORM, TOKEN). Next.js still reads its runtime env vars from .env.local.

Use pnpm as the default package manager. Fall back to npm if pnpm is not installed. The generated app should live in the current directory, not in a subdirectory.

When building a navbar or header, do NOT display the tenant/platform name. Use the ibl.ai logo instead.

Navbar: If the user wants a navbar with the profile dropdown, guide them to /iblai-navbar first. That skill creates the full navbar with logo, page links, notification bell, and profile dropdown.
Common setup (brand, conventions, env files, verification): see docs/skill-setup.md.

Prerequisites

  • Auth must be set up first (/iblai-auth)
  • MCP and skills must be set up: iblai add mcp

Step 0: Check for CLI Updates

Before running any iblai command, ensure the CLI is up to date. Run iblai --version to check the current version, then upgrade directly:

  • pip: pip install --upgrade iblai-app-cli
  • npm: npm install -g @iblai/cli@latest

This is safe to run even if already at the latest version.

Step 1: Check Environment

Before proceeding, check for a iblai.env in the project root. Look for PLATFORM, DOMAIN, and TOKEN variables. If the file does not exist or is missing these variables, tell the user: "You need an iblai.env with your platform configuration. Download the template and fill in your values: curl -o iblai.env https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/iblai.env"

Step 2: Run the Generator

iblai add profile

What Was Generated

FilePurpose
components/iblai/profile-dropdown.tsxAvatar dropdown for navbar with profile, organization, tenant switcher, and logout

The dropdown reads userData, tenant/current_tenant, and tenants from localStorage. Admin status is derived from the tenants array by matching the current tenant key against is_admin.

The dropdown shows: Profile (links to /profile), Organization (links to /account), Tenant Switcher, and Logout.

Step 3: Add a Full Profile Page

The generator creates the dropdown only. You must create the profile page manually using the Profile component (not UserProfileModal, which renders as a dialog).

Import Profile from @iblai/iblai-js/web-containers (the framework-agnostic bundle, NOT the /next bundle). This renders an inline, full-page profile editor with sidebar navigation on desktop and tabbed navigation on mobile.

Reference implementation

// app/(app)/profile/page.tsx
"use client";

import { useEffect, useState } from "react";
import { Profile } from "@iblai/iblai-js/web-containers";
import { resolveAppTenant } from "@/lib/iblai/tenant";

export default function ProfilePage() {
  const [tenantKey, setTenantKey] = useState("");
  const [username, setUsername] = useState("");
  const [isAdmin, setIsAdmin] = useState(false);
  const [ready, setReady] = useState(false);

  useEffect(() => {
    try {
      const raw = localStorage.getItem("userData");
      if (raw) {
        const parsed = JSON.parse(raw);
        setUsername(parsed.user_nicename ?? parsed.username ?? "");
      }
    } catch {}

    const resolved = resolveAppTenant();
    setTenantKey(resolved);

    try {
      const tenantsRaw = localStorage.getItem("tenants");
      if (tenantsRaw) {
        const parsed = JSON.parse(tenantsRaw);
        const match = parsed.find((t: any) => t.key === resolved);
        if (match) setIsAdmin(!!match.is_admin);
      }
    } catch {}

    setReady(true);
  }, []);

  if (!ready || !tenantKey) {
    return (
      <div className="flex flex-1 items-center justify-center">
        <p className="text-sm text-gray-400">Loading profile...</p>
      </div>
    );
  }

  return (
    <div className="mx-auto w-full flex-1 overflow-auto px-4 py-8 md:w-[75vw] md:px-0">
      <div className="rounded-lg border border-[var(--border-color)] bg-white overflow-hidden">
        <Profile
          tenant={tenantKey}
          username={username}
          isAdmin={isAdmin}
          onClose={() => {}}
          customization={{
            showPlatformName: true,
            useGravatarPicFallback: true,
          }}
          targetTab="basic"
        />
      </div>
    </div>
  );
}

Key patterns

  • White container wrapper: The SDK Profile component has no outer background. Wrap it in a bg-white rounded-lg border container so it renders as a card against the gray page background (--sidebar-bg: #fafbfc).
  • Profile vs UserProfileModal: Profile renders inline (full page). UserProfileModal renders as a dialog overlay. Use Profile for a dedicated /profile route.
  • Import path: @iblai/iblai-js/web-containers (NOT /next).

Step 4: Enable Tenant Switcher in the Dropdown

The generator does NOT enable the tenant switcher by default. You must pass the userTenants prop and set showTenantSwitcher to true:

// In profile-dropdown.tsx, add:
const userTenants = useMemo(() => {
  if (typeof window === "undefined") return [];
  try {
    const raw = localStorage.getItem("tenants");
    return raw ? JSON.parse(raw) : [];
  } catch {
    return [];
  }
}, []);

// Then pass to the component:
<UserProfileDropdown
  userTenants={userTenants}
  showTenantSwitcher
  showAccountTab
  // ...other props
/>

Without userTenants, the tenant switcher will not appear even when showTenantSwitcher is true.

Step 5: Use MCP Tools for Customization

get_component_info("UserProfileDropdown")
get_component_info("Profile")
get_component_info("MediaBox")
get_component_info("ResumeTab")

Profile Content API

The SDK Profile component handles all API calls internally. If you need to build custom profile UIs or interact with profile data programmatically, here are the APIs each tab uses.

Read before write. When calling these REST endpoints directly (e.g. via fetch or curl), always GET the current data first, merge your changes into it, then POST/PUT the full object back. Most endpoints replace the entire resource -- they do NOT merge fields. Skipping the read will silently erase fields you didn't include in the payload.

# 1. Read current state
curl -s "{lmsUrl}/api/ibl/users/manage/metadata/?username=alice" \
  -H "Authorization: Token {axd_token}" > profile.json

# 2. Merge your changes into the existing data
# 3. Write back the full object
curl -X POST "{lmsUrl}/api/ibl/users/manage/metadata/?username=alice" \
  -H "Authorization: Token {axd_token}" \
  -H "Content-Type: application/json" \
  -d @profile.json

This applies to all profile endpoints: metadata, social links, education, experience, and resume.

Two Services

Profile data lives across two backend services:

ServiceBase URLAuth HeaderManages
LMSconfig.lmsUrl()Authorization: Token {axd_token}Basic info, social links, profile image, password, account deletion
DMconfig.dmUrl()Authorization: Token {dm_token}Education, experience, companies, institutions, resume

Basic Tab

Reads and updates the user's core profile: full name, email, title, about/bio, language preference, and display toggles.

GET  {lmsUrl}/api/ibl/users/manage/metadata/?username={username}
POST {lmsUrl}/api/ibl/users/manage/metadata/?username={username}

Read response fields:

{
  fullName: string;
  email: string;
  username: string;
  title: string;
  about: string;       // bio/description
  language: string;     // "en", "es", "fr"
  enable_sidebar_ai_mentor_display: boolean;
  enable_skills_leaderboard_display: boolean;
}

Update payload:

{
  name: string;
  username: string;
  title: string;
  about: string;
  public_metadata: { language: string };
  enable_sidebar_ai_mentor_display: boolean;
  enable_skills_leaderboard_display: boolean;
  email?: string;  // only include if changed
}

Profile image:

POST {lmsUrl}/api/user/v1/accounts/{username}/image   // upload (FormData with file)
GET  {lmsUrl}/api/user/v1/accounts/{username}          // read (returns profile_image.image_url_full)
POST {lmsUrl}/api/profile_images/v1/{username}/remove  // remove

Social Tab

Reads and updates social media links (Facebook, LinkedIn, X/Twitter).

Uses the same endpoint as Basic:

GET  {lmsUrl}/api/ibl/users/manage/metadata/?username={username}
POST {lmsUrl}/api/ibl/users/manage/metadata/?username={username}

Social links in response:

{
  social_links: [
    { platform: "facebook", social_link: "https://facebook.com/username" },
    { platform: "twitter", social_link: "https://x.com/username" },  // stored as "twitter"
    { platform: "linkedin", social_link: "https://linkedin.com/in/username" }
  ]
}

Update payload:

{
  social_links: [
    { platform: "facebook", social_link: string },
    { platform: "twitter", social_link: string },
    { platform: "linkedin", social_link: string }
  ],
  username: string
}

Validation rules:

  • Facebook: https://facebook.com/ prefix, letters/numbers/hyphens/periods only
  • LinkedIn: https://linkedin.com/in/ prefix, min 5 chars, letters/numbers/periods
  • X/Twitter: https://x.com/ prefix, 4-15 chars, letters/numbers/underscores

Education Tab

CRUD operations for education entries. Uses the DM career API.

GET    {dmUrl}/api/career/orgs/{org}/education/users/{username}/
POST   {dmUrl}/api/career/orgs/{org}/education/users/{username}/
PUT    {dmUrl}/api/career/orgs/{org}/education/users/{username}/?id={education_id}
DELETE {dmUrl}/api/career/orgs/{org}/education/users/{username}/?id={education_id}

Education schema:

{
  id: number;
  institution: { id: number; name: string };
  institution_id: number;        // required for create/update
  degree: string;
  field_of_study: string;
  start_date: string;            // "YYYY-MM-DD"
  end_date: string | null;
  is_current: boolean;
  grade: string;
  activities: string;
  description: string;
  data: Record<string, any>;     // arbitrary metadata
  metadata: Record<string, any>;
}

Institutions (lookup for the institution picker):

GET  {dmUrl}/api/career/orgs/{org}/institutions/users/{username}/
POST {dmUrl}/api/career/orgs/{org}/institutions/users/{username}/

Institution create payload:

{ name: string; institution_type: InstitutionTypeEnum; established_year?: number }

Experience Tab

CRUD operations for professional experience entries.

GET    {dmUrl}/api/career/orgs/{org}/experience/users/{username}/
POST   {dmUrl}/api/career/orgs/{org}/experience/users/{username}/
PUT    {dmUrl}/api/career/orgs/{org}/experience/users/{username}/?id={experience_id}
DELETE {dmUrl}/api/career/orgs/{org}/experience/users/{username}/?id={experience_id}

Experience schema:

{
  id: number;
  company: { id: number; name: string };
  company_id: number;            // required for create/update
  title: string;
  employment_type: string;       // "Full-time", "Part-time", "Contract", "Freelance", "Internship"
  location: string;
  start_date: string;            // "YYYY-MM-DD"
  end_date: string | null;
  is_current: boolean;
  description: string;
  data: Record<string, any>;
  metadata: Record<string, any>;
}

Companies (lookup for the company picker):

GET  {dmUrl}/api/career/orgs/{org}/companies/users/{username}/
POST {dmUrl}/api/career/orgs/{org}/companies/users/{username}/

Company create payload:

{ name: string; industry?: string; website?: string; logo_url?: string }

Resume Tab

Upload and view PDF resumes.

GET  {dmUrl}/api/career/resume/orgs/{org}/users/{username}/
POST {dmUrl}/api/career/resume/orgs/{org}/users/{username}/
PUT  {dmUrl}/api/career/resume/orgs/{org}/users/{username}/

Upload (FormData):

user: {username}
platform: {org}
resume: File          // PDF only, max 25MB -- marks as CV
additional_files: File  // general file upload (not CV)

Response:

{
  id: number;
  user: number;
  platform: string;
  files: [{ name: string; url: string; type: string }];
  links: [{ url: string }];
}

Security Tab

Password reset and account deletion.

POST {lmsUrl}/account/password              // sends reset email
POST {dmUrl}/api/core/users/delete/          // account deletion (self-retire)

Password reset sends an email to the user's registered address. Account deletion payload: {username: string}.

RTK Query Hooks (SDK Exports)

The SDK's data-layer exports these hooks for all career operations:

import {
  useGetUserEducationQuery,
  useCreateUserEducationMutation,
  useUpdateUserEducationMutation,
  useDeleteUserEducationMutation,
  useGetUserExperienceQuery,
  useCreateUserExperienceMutation,
  useUpdateUserExperienceMutation,
  useDeleteUserExperienceMutation,
  useGetUserInstitutionsQuery,
  useCreateUserInstitutionMutation,
  useGetUserCompaniesQuery,
  useCreateUserCompanyMutation,
  useGetUserResumeQuery,
  useCreateUserResumeMutation,
} from "@iblai/iblai-js/data-layer";

For user metadata (basic/social):

import {
  useGetUserMetadataQuery,
  useUpdateUserMetadataMutation,
  useUploadProfileImageMutation,
  useGetUserMetadataEdxQuery,
  useResetPasswordMutation,
} from "@iblai/iblai-js/data-layer";

Building a Custom Career API Slice

If you need career APIs without the SDK's built-in hooks, build a standard RTK Query slice with fetchBaseQuery and one endpoint per row in the endpoint tables above. Use Authorization: Token {dm_token} (from localStorage), and tag invalidation on ["education", "experience", "institution", "company", "resume"].


User Metadata API

The ibl.ai platform provides per-user metadata storage via the Mentor Metadata endpoint. This is useful for storing arbitrary JSON data scoped to a specific user and mentor (e.g. application progress, preferences, onboarding state).

Endpoints

GET  {dmUrl}/api/ai/mentor/orgs/{org}/users/{username}/metadata?mentor={mentorId}
POST {dmUrl}/api/ai/mentor/orgs/{org}/metadata/        body: { mentor_id, metadata }
  • Auth: Authorization: Token {axd_token} (from localStorage)
  • Scope: Per-user, per-mentor; isolated.
  • Schema: Arbitrary JSON.
  • Merge behavior: POST merges new keys with existing metadata (does not replace the entire object).

AI Profile Memory API

The platform stores AI-learned facts about a user as tag/detail pairs. This powers the "AI Memory" tab in the profile modal.

GET    {dmUrl}/api/ai-mentor/orgs/{org}/users/{user_id}/ai-user-profile-memory/
POST   {dmUrl}/api/ai-mentor/orgs/{org}/users/{user_id}/ai-user-profile-memory/
DELETE {dmUrl}/api/ai-mentor/orgs/{org}/users/{user_id}/ai-user-profile-memory/{tag}/

Create/Read:

// Request
{ tag: "favorite-animal", detail: "my favorite animal is cat" }

// Response (array of entries)
[{ tag: "favorite-animal", detail: "my favorite animal is cat" }]

Auth: Uses axd_token from localStorage.


Chat Privacy Settings

Users can control how their chat data is stored.

GET  {dmUrl}/api/ai-account/orgs/{org}/users/{user_id}/chat-privacy-config/
GET  {dmUrl}/api/ai-account/orgs/{org}/users/{user_id}/chat-privacy-settings/
POST {dmUrl}/api/ai-account/orgs/{org}/users/{user_id}/chat-privacy-settings/

Privacy modes: normal, anonymized, disabled

The config endpoint returns whether the platform has this feature enabled. The settings endpoint reads/writes the user's preference.


Media Upload (MediaBox)

The SDK provides a MediaBox component for file and link uploads. It renders a tabbed interface with a file upload zone and a link input field, plus a list of previously uploaded files/links.

Import

import { MediaBox, type UploadedFile } from "@iblai/iblai-js/web-containers/next";

Props

PropTypeDescription
uploadedMediaUploadedFile[]Previously uploaded files/links to display
isLoadingboolean?Show loading state
isErrorboolean?Show error state
isUploadingboolean?Show upload-in-progress state
resumeCheckboxEnabledboolean?Show "This is my CV" checkbox
onUploadFile(file: File, isResume: boolean) => voidCalled when a file is selected
onUploadLink(url: string) => voidCalled when a link is submitted
onError(message: string) => voidCalled on validation errors

UploadedFile type

interface UploadedFile {
  name: string;
  url: string;
  type?: string;  // "link" for links, MIME type for files
}

Peer dependency

MediaBox requires @tanstack/react-form:

pnpm add @tanstack/react-form

Backend: Career/Resume API

MediaBox is a presentational component -- it does not handle uploads itself. You must connect it to the Career/Resume API for persistent storage:

GET/PUT/POST  /api/career/resume/orgs/{org}/users/{username}/
Connecting MediaBox to the Career API
import { useMemo } from "react";
import { toast } from "sonner";
import { MediaBox, type UploadedFile } from "@iblai/iblai-js/web-containers/next";
import { useGetUserResumeQuery, useCreateUserResumeMutation } from "@/services/career-api";
import { resolveAppTenant } from "@/lib/iblai/tenant";

function getUserName(): string {
  if (typeof window === "undefined") return "";
  try {
    const raw = localStorage.getItem("userData");
    return raw ? JSON.parse(raw).user_nicename ?? "" : "";
  } catch { return ""; }
}

export function DocumentUploads() {
  const org = useMemo(() => resolveAppTenant(), []);
  const username = useMemo(() => getUserName(), []);

  const { data, isLoading, isError, refetch } = useGetUserResumeQuery(
    { org, username },
    { skip: !org || !username }
  );
  const [createResume, { isLoading: isUploading }] = useCreateUserResumeMutation();

  const uploadedMedia: UploadedFile[] = useMemo(() => {
    if (!data) return [];
    const files = (data.files ?? []).map((f) => ({ name: f.name, url: f.url, type: f.type }));
    const links = (data.links ?? []).map((l) => ({ name: l.url, url: l.url, type: "link" }));
    return [...files, ...links];
  }, [data]);

  async function handleUploadFile(file: File, isResume: boolean) {
    const formData = new FormData();
    formData.append("user", username);
    formData.append("platform", org);
    formData.append(isResume ? "resume" : "additional_files", file);
    try {
      await createResume({ org, username, resume: formData, method: "POST" }).unwrap();
      toast.success("File uploaded successfully");
      refetch();
    } catch { toast.error("Failed to upload file"); }
  }

  async function handleUploadLink(url: string) {
    const formData = new FormData();
    formData.append("user", username);
    formData.append("platform", org);
    const existingLinks = data?.links ?? [];
    existingLinks.forEach((link, index) => {
      formData.append(`link_${existingLinks.length + 1 - index}`, link.url);
    });
    formData.append("link_1", url);
    try {
      await createResume({ org, username, resume: formData }).unwrap();
      toast.success("Link added successfully");
      refetch();
    } catch { toast.error("Failed to add link"); }
  }

  if (!org || !username) {
    return <p className="text-[14px] text-[#86868b]">Please sign in to upload documents.</p>;
  }

  return (
    <MediaBox
      uploadedMedia={uploadedMedia}
      isLoading={isLoading}
      isError={isError}
      isUploading={isUploading}
      resumeCheckboxEnabled={true}
      onUploadFile={handleUploadFile}
      onUploadLink={handleUploadLink}
      onError={(msg) => toast.error(msg)}
    />
  );
}
Key details
  • Auth: Uses dm_token from localStorage (NOT axd_token)
  • FormData fields: user (username), platform (org key), resume (file, marks as CV) or additional_files (file, general upload)
  • Links: Append numbered link_N fields. Preserve existing links when adding a new one
  • Persistent: Files are stored on the user's profile permanently (unlike chat file uploads which are session-scoped)

Career Profile Tabs (Standalone)

The SDK also exports individual career profile tabs that can be used outside the full Profile component:

ResumeTab

import { ResumeTab } from "@iblai/iblai-js/web-containers";
<ResumeTab org={tenantKey} username={username} />

Renders a resume upload and display interface. Props: org (string), username (string).

EducationTab

import { EducationTab } from "@iblai/iblai-js/web-containers";
<EducationTab org={tenantKey} username={username} />

Renders education background management (add/edit/delete education entries). Props: org (string), username (string).

ExperienceTab

import { ExperienceTab } from "@iblai/iblai-js/web-containers";
<ExperienceTab org={tenantKey} username={username} />

Renders professional experience management. Props: org (string), username (string).

Dialogs

These companion dialogs can be used alongside the tabs:

ComponentImportDescription
EducationDialog@iblai/iblai-js/web-containersDialog for adding/editing education entries
ExperienceDialog@iblai/iblai-js/web-containersDialog for adding/editing experience entries
CompanyDialog@iblai/iblai-js/web-containersCompany selection dialog
InstitutionDialog@iblai/iblai-js/web-containersInstitution selection dialog

<UserProfileDropdown> Props

The generated dropdown component. Import from @iblai/iblai-js/web-containers/next.

PropTypeDescription
usernamestringUsername
tenantKeystringTenant/org key
userIsAdminbooleanShows admin badge + settings
userTenantsTenant[]Required for tenant switcher -- full tenant list from localStorage
showProfileTabbooleanShow profile link
showAccountTabbooleanShow account settings link
showTenantSwitcherbooleanShow tenant switcher (needs userTenants)
showLogoutButtonbooleanShow logout button
showHelpLinkbooleanShow help link
authURLstringAuth service URL
onLogout() => voidLogout callback
onTenantChange(tenant: string) => voidCalled when user switches tenant -- must set app_tenant in localStorage
onTenantUpdate(tenant: Tenant) => voidCalled when tenant data updates -- must set app_tenant in localStorage
classNamestring?Additional CSS class
dropdownClassNamestring?CSS class for dropdown panel
avatarSizenumber?Avatar size in pixels
metadata{help_center_url?: string; show_help?: boolean}Platform metadata for help link
metadataLoadedboolean?Whether metadata has finished loading
enableMemoryTabboolean?Show AI memory management tab
enableCatalogInviteboolean?Enable catalog invite feature
enableRbacboolean?Enable RBAC permission checks
isModalOpenboolean?Control profile modal open state externally
onModalOpenChange(open: boolean) => voidCallback when modal open state changes
defaultActiveTabstring?Default tab when profile modal opens
onAccountDeleted() => voidCallback after account deletion

<Profile> Props (Full-Page Profile)

Import from @iblai/iblai-js/web-containers.

PropTypeDescription
tenantstringTenant/org key
usernamestringUsername
isAdminbooleanAdmin flag
onClose() => voidClose callback
customizationobjectSee below
targetTabstringInitial tab: basic, social, education, experience, resume, security
enableMemoryTabboolean?Show AI memory management tab
localLLMPropsobject?Props for local LLM tab (Tauri desktop only)
onAccountDeleted() => voidCallback after account deletion

Customization object

{
  showMentorAIDisplayCheckbox?: boolean;  // Show "visible on MentorAI" toggle
  showLeaderboardDisplayCheckbox?: boolean;  // Show leaderboard opt-in
  showUsernameField?: boolean;  // Show username field (read-only)
  showPlatformName?: boolean;  // Show platform/tenant name badge
  useGravatarPicFallback?: boolean;  // Use Gravatar when no profile pic
}

<UserProfileModal> Props (Profile + Account Modal)

For a profile editing modal (used by the MentorAI reference app), import UserProfileModal from @iblai/iblai-js/web-containers/next. This is a dialog that combines profile editing and account settings in one overlay.

The modal shows Profile tabs (basic, social, education, experience, resume, security) and Account tabs (organization, management, integrations, billing). Billing/purchases is on the Account side, not the Profile side.

Required

PropTypeDescription
isOpenbooleanWhether the modal is visible
onClose() => voidClose callback
params{tenantKey: string; mentorId?: string; isAdmin?: boolean}Tenant key, optional mentor ID and admin flag
authURLstringAuth service URL (from config.authUrl())

Optional

PropTypeDescription
tenantsTenant[]Full list of user tenants from localStorage
targetTabstringInitial tab: basic, social, education, experience, resume, security, organization, management, integrations, billing
showPlatformNamebooleanShow tenant name badge
useGravatarPicFallbackbooleanUse Gravatar when no profile pic
currentSPAstringCurrent app identifier (e.g., "agent")
currentPlatformBaseDomainstringBase domain for custom domain settings
billingEnabledbooleanEnable billing tab (requires Stripe integration)
billingURLstringStripe billing portal URL
topUpEnabledbooleanEnable credit top-up
topUpURLstringStripe top-up URL
onTenantUpdate(tenant: Tenant) => voidCalled when tenant is updated
onBillingTabRequest`() => Promise<void> \void`Called when billing tab is opened -- fetch billing data
onUpgradeClick() => voidCalled when upgrade button is clicked
onAccountDeleted() => voidCalled after account deletion

Step 6: Verify

Run /iblai-ops-test before telling the user the work is ready:

  1. pnpm build -- must pass with zero errors
  2. pnpm test -- vitest must pass
  3. Start dev server and touch test: pnpm dev & npx playwright screenshot http://localhost:3000/profile /tmp/profile.png

Important Notes

  • Redux store: Must include mentorReducer and mentorMiddleware
  • initializeDataLayer(): 5 args (v1.2+)
  • @reduxjs/toolkit: Deduplicated via webpack aliases in next.config.ts
  • Admin detection: Derived from tenants array in localStorage
  • SDK hardcoded styles: The SDK Profile component uses bg-white and bg-gray-50 internally. Do NOT override these. Instead, wrap the component in a white container so it renders correctly against the gray page background.
  • Billing/Purchases: Lives on the Account page (/iblai-account), not on the Profile page. Use UserProfileModal with targetTab="billing" and billingEnabled={true} to access it from the combined modal.
  • Brand guidelines: BRAND.md

平台分布

Codex

37.87%
按下载量换算140

Claude

32.03%
按下载量换算119

Cursor

16.96%
按下载量换算63

Gemini CLI

9.08%
按下载量换算34

安全审计

Gen Agent Trust Hub

通过

Socket

可疑

Snyk

可疑

权限和风险

接触敏感数据

该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。来源安全扫描存在提醒或未通过项,安装前请自行复核。目前只有一个公开来源,建议同时核对源仓库。

继续浏览同类 Skills